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.

你对此有什么看法?


当前回答

我承认使用了断言,但没有考虑适当的错误报告。然而,这并不意味着它们在正确使用时是非常有用的。

They are especially useful for if you want to follow the "Crash Early" principle. For example suppose you're implementing a reference counting mechanism. At certain locations in your code you know that the refcount should be zero or one. And also suppose that if the refcount is wrong the program won't crash immediately but during the next message loop at which point it will be difficult to find out why things went wrong. An assert would have been helpful in detecting the error closer to its origin.

其他回答

这种情况经常出现,我认为让断言辩护令人困惑的一个问题是,它们通常基于参数检查。所以考虑一下这个不同的例子,当你使用断言时:

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

您对输入使用异常是因为您预计有时会得到错误的输入。您断言对列表进行排序是为了帮助您找到算法中的bug,根据定义,这是您所不期望的。断言只存在于调试版本中,因此即使检查的开销很大,您也不介意对例程的每次调用都进行检查。

您仍然需要对产品代码进行单元测试,但这是确保代码正确的一种不同的补充方式。单元测试确保您的例程符合其接口,而断言是一种更细粒度的方法,以确保您的实现完全按照您的期望进行。

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

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

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

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

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

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

我更倾向于避免在调试和发布中做不同事情的代码。

但是,在一个条件下中断调试器并获得所有文件/行信息,以及确切的表达式和确切的值是有用的。

拥有一个“只在调试中评估条件”的断言可能是一种性能优化,因此,它只在0.0001%的程序中有用——人们知道他们在做什么。在所有其他情况下,这是有害的,因为表达式实际上可能改变程序的状态:

assert(2 == shroedingerscat . getnummears ()); 会使程序在调试和发布时做不同的事情。

我们开发了一组assert宏,可以在调试版和发布版中抛出异常。例如,THROW_UNLESS_EQ(a, 20);what()消息同时包含文件、行和a的实际值,等等,将抛出异常。只有宏才有这个功能。调试器可以配置为在特定异常类型的'throw'时中断。