Go语言的创造者写道:

Go doesn't provide assertions. They are undeniably convenient, but our experience has been that programmers use them as a crutch to avoid thinking about proper error handling and reporting. Proper error handling means that servers continue operation after non-fatal errors instead of crashing. Proper error reporting means that errors are direct and to the point, saving the programmer from interpreting a large crash trace. Precise errors are particularly important when the programmer seeing the errors is not familiar with the code.

你对此有什么看法?


当前回答

如果您所谈论的断言意味着程序抛出然后存在,那么断言可能非常糟糕。这并不是说它们总是错误的使用,它们是一种很容易被误用的结构。他们也有很多更好的选择。这样的事情很容易被称为邪恶。

例如,第三方模块(或任何模块)几乎不应该退出调用程序。这并没有给调用程序的程序员任何控制程序此时应该承担的风险。在许多情况下,数据是如此重要,即使保存损坏的数据也比丢失数据要好。断言可能会迫使您丢失数据。

断言的一些替代方法:

使用调试器, 控制台/数据库/其他日志 异常 其他类型的错误处理

参考:

http://ftp.gnu.org/old-gnu/Manuals/nana-1.14/html_node/nana_3.html http://www.lenholgate.com/blog/2005/09/assert-is-evil.html Go不提供断言,并且有很好的理由:http://golang.org/doc/faq#assertions http://c2.com/cgi/wiki?DoNotUseAssertions

甚至主张assert的人也认为它们应该只用于开发而不是生产:

http://codebetter.com/gregyoung/2007/12/12/asserts-are-not-evil/ http://www.codeproject.com/Articles/6404/Assert-is-your-friend http://parabellumgames.wordpress.com/using-asserts-for-debugging/

This person says that asserts should be used when the module has potentially corrupted data that persists after an exception is thrown: http://www.advogato.org/article/949.html . This is certainly a reasonable point, however, an external module should never prescribe how important corrupted data is to the calling program (by exiting "for" them). The proper way to handle this is by throwing an exception that makes it clear that the program may now be in an inconsistent state. And since good programs mostly consist of modules (with a little glue code in the main executable), asserts are almost always the wrong thing to do.

其他回答

断言并不邪恶,但很容易被滥用。我非常同意“断言经常被用作一种拐杖,以避免考虑正确的错误处理和报告”的说法。我经常看到这种情况。

就我个人而言,我确实喜欢使用断言,因为它们记录了我在编写代码时可能做出的假设。如果在维护代码时这些假设被打破了,那么可以在测试期间检测到问题。但是,在进行产品构建时(即使用#ifdefs),我确实强调要从代码中剥离出每个断言。通过剥离产品构建中的断言,我消除了任何人将其误用为拐杖的风险。

断言还有另一个问题。断言只在运行时进行检查。但是通常情况下,您想要执行的检查可以在编译时执行。最好在编译时检测问题。对于c++程序员,boost提供了BOOST_STATIC_ASSERT,它允许您执行此操作。对于C程序员,本文(链接文本)描述了一种可用于在编译时执行断言的技术。

总之,我遵循的经验法则是:不要在生产构建中使用断言,如果可能的话,只对在编译时无法验证的东西使用断言(即,必须在运行时检查)。

我从不使用assert(),示例通常是这样的:

int* ptr = new int[10];
assert(ptr);

这很糟糕,我从来没有这样做过,如果我的游戏分配了一堆怪物怎么办?为什么我要让游戏崩溃,相反,你应该优雅地处理错误,所以可以这样做:

CMonster* ptrMonsters = new CMonster[10];
if(ptrMonsters == NULL) // or u could just write if(!ptrMonsters)
{
    // we failed allocating monsters. log the error e.g. "Failed spawning 10 monsters".
}
else
{
    // initialize monsters.
}

我最近开始在我的代码中添加一些断言,这是我一直在做的:

我在心里把代码分为边界代码和内部代码。边界代码是处理用户输入、读取文件和从网络获取数据的代码。在这段代码中,我在一个循环中请求输入,该循环仅在输入有效时退出(在交互式用户输入的情况下),或者在不可恢复的文件/网络损坏数据的情况下抛出异常。

内部代码就是一切。例如,在我的类中设置变量的函数可以定义为

void Class::f (int value) {
    assert (value < end);
    member = value;
}

从网络获取输入的函数可以这样读:

void Class::g (InMessage & msg) {
    int const value = msg.read_int();
    if (value >= end)
        throw InvalidServerData();
    f (value);
}

This gives me two layers of checks. Anything where the data is determined at run-time always gets an exception or immediate error handling. However, that extra check in Class::f with the assert statement means that if some internal code ever calls Class::f, I still have a sanity check. My internal code might not pass a valid argument (because I may have calculated value from some complex series of functions), so I like having the assertion in the setting function to document that regardless of who is calling the function, value must not be greater than or equal to end.

这似乎符合我在一些地方读到的内容,即在一个功能良好的程序中,断言应该是不可能违反的,而例外应该是针对仍然可能发生的异常和错误情况。因为理论上我要验证所有输入,所以我的断言不应该被触发。如果是,我的程序就错了。

如果您所谈论的断言意味着程序抛出然后存在,那么断言可能非常糟糕。这并不是说它们总是错误的使用,它们是一种很容易被误用的结构。他们也有很多更好的选择。这样的事情很容易被称为邪恶。

例如,第三方模块(或任何模块)几乎不应该退出调用程序。这并没有给调用程序的程序员任何控制程序此时应该承担的风险。在许多情况下,数据是如此重要,即使保存损坏的数据也比丢失数据要好。断言可能会迫使您丢失数据。

断言的一些替代方法:

使用调试器, 控制台/数据库/其他日志 异常 其他类型的错误处理

参考:

http://ftp.gnu.org/old-gnu/Manuals/nana-1.14/html_node/nana_3.html http://www.lenholgate.com/blog/2005/09/assert-is-evil.html Go不提供断言,并且有很好的理由:http://golang.org/doc/faq#assertions http://c2.com/cgi/wiki?DoNotUseAssertions

甚至主张assert的人也认为它们应该只用于开发而不是生产:

http://codebetter.com/gregyoung/2007/12/12/asserts-are-not-evil/ http://www.codeproject.com/Articles/6404/Assert-is-your-friend http://parabellumgames.wordpress.com/using-asserts-for-debugging/

This person says that asserts should be used when the module has potentially corrupted data that persists after an exception is thrown: http://www.advogato.org/article/949.html . This is certainly a reasonable point, however, an external module should never prescribe how important corrupted data is to the calling program (by exiting "for" them). The proper way to handle this is by throwing an exception that makes it clear that the program may now be in an inconsistent state. And since good programs mostly consist of modules (with a little glue code in the main executable), asserts are almost always the wrong thing to do.

不,只要您按照预期使用assert,它就没有错。

也就是说,它应该用于在调试期间捕捉“不可能发生”的情况,而不是正常的错误处理。

断言:程序逻辑本身的失败。 错误处理:错误的输入或系统状态,不是由于程序中的错误造成的。