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非常有用,可以在出现意外错误时通过在出现问题的第一个迹象时停止程序来节省大量回溯时间。

另一方面,断言很容易被滥用。

int quotient(int a, int b){
    assert(b != 0);
    return a / b;
}

正确的说法应该是:

bool quotient(int a, int b, int &result){
    if(b == 0)
        return false;

    result = a / b;
    return true;
}

所以…从长远来看……从大局来看……我必须同意断言可能会被滥用。我一直都这么做。

不,去做和断言都不是坏事。但两者都可能被误用。

Assert用于完整性检查。如果它们不正确,就会杀死程序。不是为了验证或替换错误处理。

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

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

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

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.

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

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

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.

当我看到这个的时候,我真想踢作者的头。

我在代码中一直使用断言,并最终在编写更多代码时将它们全部替换掉。当我还没有编写所需的逻辑时,我就会使用它们,当我运行到代码时,我想要得到警告,而不是编写一个将在项目接近完成时删除的异常。

异常也更容易融入到产品代码中,这是我不喜欢的。断言比抛出新异常("一些通用的msg或'pretend i am An assert'")更容易注意到;