caf*_*caf 318
不,assert只要您按预期使用它就没有任何问题.
也就是说,它应该用于在调试期间捕获"不可能发生"的情况,而不是正常的错误处理.
gah*_*ooa 106
不,既不是goto也不assert邪恶.但两者都可能被滥用.
断言是为了进行健全性检查.如果不正确,应该杀死程序的东西.不用于验证或替代错误处理.
jal*_*alf 61
按照这种逻辑,断点也是邪恶的.
断言应该用作调试辅助,而不是其他任何东西."邪恶"是指您尝试使用它们而不是错误处理.
断言可以帮助您,程序员,检测和修复不存在的问题,并验证您的假设是否成立.
它们与错误处理无关,但不幸的是,一些程序员滥用它们,然后宣称它们是"邪恶的".
arh*_*aco 39
我喜欢断言很多.当我第一次构建应用程序时(或许对于新域),我发现它非常有用.而不是做非常花哨的错误检查(我会考虑过早优化)我快速编码,我添加了很多断言.在我更了解事情是如何工作之后,我会重写并删除一些断言并更改它们以便更好地处理错误.
由于断言,我花了很多时间编写/调试程序.
我也注意到这些断言帮助我想到许多可能破坏我程序的事情.
Ran*_*ku' 30
作为附加信息,go提供了内置功能panic.这可以用来代替assert.例如
if x < 0 {
panic("x is less than 0");
}
Run Code Online (Sandbox Code Playgroud)
panic将打印堆栈跟踪,因此在某种程度上它的目的是assert.
jto*_*lle 13
这出现了很多,我认为一个使断言防御混乱的问题是它们通常基于参数检查.因此,请考虑使用断言时的不同示例:
build-sorted-list-from-user-input(input)
throw-exception-if-bad-input(input)
...
//build list using algorithm that you expect to give a sorted list
...
assert(is-sorted(list))
end
Run Code Online (Sandbox Code Playgroud)
您对输入使用异常,因为您希望有时会得到错误的输入.您声明列表已排序,以帮助您找到算法中的错误,根据定义,您不会发现该错误.断言仅在调试版本中,因此即使检查很昂贵,您也不介意在每次调用例程时都这样做.
您仍然需要对生产代码进行单元测试,但这是确保代码正确的另一种补充方法.单元测试确保您的例程符合其界面,而断言是一种更精细的方式,以确保您的实现完全符合您的预期.
断言不是邪恶的,但很容易被滥用.我同意这样的说法:"断言经常被用作拐杖,以避免考虑正确的错误处理和报告".我经常看到这个.
就个人而言,我喜欢使用断言,因为它们记录了我在编写代码时可能做出的假设.如果在维护代码时破坏了这些假设,则可以在测试期间检测到问题.但是,我确实在进行生产构建时(即使用#ifdefs)从我的代码中删除每个断言.通过剥离生产构建中的断言,我消除了任何人滥用它们作为拐杖的风险.
断言还有另一个问题.断言仅在运行时检查.但通常情况下,您希望执行的检查可能是在编译时执行的.最好在编译时检测问题.对于C++程序员,boost提供了BOOST_STATIC_ASSERT,允许您执行此操作.对于C程序员,本文(链接文本)描述了一种可用于在编译时执行断言的技术.
总之,我遵循的经验法则是:不要在生产构建中使用断言,并且如果可能的话,只对在编译时无法验证的事物使用断言(即,必须在运行时检查).
我承认在没有考虑正确的错误报告的情况下使用了断言.但是,如果使用得当,它们会非常有用.
如果您想遵循"早期崩溃"原则,它们尤其有用.例如,假设您正在实现引用计数机制.在代码中的某些位置,您知道引用计数应为零或一.并且假设如果引用计数错误,程序将不会立即崩溃,但在下一个消息循环期间,将很难找出出错的原因.断言有助于检测更接近其原点的错误.
我不喜欢强烈的断言.我不会说他们是邪恶的.
基本上断言将执行与未经检查的异常相同的事情,唯一的例外是不应该为最终产品保留断言(通常).
如果您在调试和构建系统时为自己构建安全网,为什么要拒绝为您的客户,支持服务台或任何将使用您当前正在构建的软件的安全网.仅对断言和异常情况使用异常.通过创建适当的异常层次结构,您将能够非常快速地识别出另一个异常层次结构.除此之外,断言仍然存在,并且可以在失败的情况下提供有价值的信息,否则将丢失.
因此,我通过完全删除断言并强制程序员使用异常来处理这种情况,完全理解Go的创建者.对此有一个简单的解释,例外只是一个更好的机制,为什么坚持古老的断言?
我更喜欢避免在调试和发布中执行不同操作的代码.
在一个条件下打破调试器并且所有文件/行信息都很有用,但确切的表达式和确切的值也是如此.
具有"仅在调试中评估条件"的断言可能是性能优化,因此仅在0.0001%的程序中有用 - 人们知道他们在做什么.在所有其他情况下,这是有害的,因为表达式实际上可能改变程序的状态:
assert(2 == ShroedingersCat.GetNumEars());
会使程序在调试和发布中做不同的事情.
我们开发了一组断言宏,它会引发异常,并在调试版和发行版中都这样做.例如,THROW_UNLESS_EQ(a, 20);会抛出具有文件,行和a的实际值的what()消息的异常,依此类推.只有宏才能拥有这种力量.调试器可以配置为在特定异常类型的'throw'处中断.