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.

你对此有什么看法?


当前回答

我对这些捍卫assert的答案的问题是,没有人清楚地说明它与常规致命错误的不同之处,以及为什么断言不能成为异常的子集。现在,如果异常从未被捕获,该怎么办?从命名法上看,这是一种断言吗?而且,为什么要在语言中强加一个可以引发/nothing/可以处理的异常的限制呢?

其他回答

我很喜欢用断言。我发现当我第一次构建应用程序(可能是一个新的领域)时,它非常有用。我没有做非常花哨的错误检查(我认为是不成熟的优化),而是快速编码,并添加了大量断言。在我了解了更多事情的工作原理后,我重新编写并删除了一些断言并更改它们以更好地处理错误。

因为断言,我花更少的时间编码/调试程序。

我还注意到,断言可以帮助我想到许多可能破坏程序的东西。

Assert被滥用用于错误处理,因为它的输入更少。

因此,作为语言设计者,他们应该看到,适当的错误处理可以用更少的输入完成。因为异常机制太冗长而排除assert并不是解决方案。哦,等等,Go也没有异常。太糟糕了:)

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

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

断言的一些替代方法:

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

参考:

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.

按照这种逻辑,断点也是邪恶的。

断言应该用作调试辅助,而不是其他。“邪恶”是当你试图使用它们而不是错误处理时。

断言的存在是为了帮助程序员检测和修复不可能存在的问题,并验证您的假设是否正确。

它们与错误处理无关,但不幸的是,一些程序员滥用它们,然后宣称它们是“邪恶的”。

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

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

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

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.

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