bool fn()
{
if(something bad happen)
return false;
..
}
void gn()
{
assert(something == true);
..
}
当我在生产代码中编写函数时,我应该采用哪种方式 选择?
答案 0 :(得分:5)
Assert
,至少在.NET中,用于测试主要是。它的具体用法简洁明了here:
断言最好用于仅在以下所有条件成立时测试条件:
* the condition should never be false if the code is correct,
* the condition is not so trivial so as to obviously be always true, and
* the condition is in some sense internal to a body of software.
在生产代码中,我推荐第一种方法;或try/catch
如果“事情不好”从未发生过;如果是特殊情况。
如果你有一个永远或永远不存在的不变量(无论系统的状态如何),那么除了测试用例之外,这是Assert
的一个很好的候选者。
我在生产代码中看到过断言;通常在design-by-contract style code。我在单元测试中经常看到它们。
答案 1 :(得分:3)
当“发生了一些不好的事情”=特殊情况时,甚至考虑使用Exception ......
答案 2 :(得分:3)
将assert用于文档并确认程序不变量(您知道它将永远为真)hold。除了一个简单的程序之外,您在编写代码时会对问题的理解发展,因此较旧的代码可能具有不同的模型,而断言将有助于解决这个问题。
对于可以更改的内容(特别是在程序控件之外),您需要能够报告错误(例如,传递给库函数的invaid参数值,文件不存在),使用平台/语言首选机制(例外,返回值,...)。
答案 3 :(得分:2)
你的“返回虚假”也被称为 GuardClause - 正如Ward Cunningham所解释的那样:
... [G] uards与断言类似 在这两方面都保护了后续 来自特殊情况的代码。警卫不同 从断言中他们做出了 对逻辑的有形贡献 该方法因而无法安全 作为优化的一部分省略。一世 借用了守卫这个词 EwDijkstra在命名这种模式时。
如果您的保护条款有任何复杂性,使用BouncerPattern进行封装通常会有所帮助。
正如Ward指出的那样,当代码可以安全地省略时,你应该使用断言。如果您的语言中有assert
个关键字,编译器通常会从生产代码中删除断言。
今天我们认识到,在大多数情况下,在代码中放置断言并不是一个好主意。经典的关注点分离。 从代码中分离断言,在单元测试中封装它们。这消除了在不分发断言的情况下重新编译代码的复杂性(您不会分发测试......),并且还为您提供了一套可以连续运行以捕获回归并推动重构的测试。
其他答案提到了按合同设计,它将这些问题完全从您的代码中解释出来,并将其置于已声明的前置条件,后置条件和围绕相关代码强制执行的不变量中。如果您经常这样做,您可以考虑根据您的语言查看“按合同设计”框架。
答案 4 :(得分:1)
恕我直言,assert
是在调试环境中断言开发人员发生意外(错误)的事情。并非所有断言都必须是关键的,并且开发人员需要将断言置于真正的失败之中。
在发布模式下,只有在错误很严重时才需要返回false,并且没有必要继续执行。
答案 5 :(得分:1)
如果代码工作正常,那么在不应该发生错误的情况下使用断言。一个例子:
int div( int a, int b ) {
assert( b != 0 );
return a / b;
}
这里,调用代码有责任确保永远不会使用第二个零参数调用div()。如果是,则代码处于未知状态,应该终止。
使用if()...在可以处理的错误发生时返回。例如,打开文件可能会失败,应由程序检测和处理 - 失败不会使程序进入未知状态。
答案 6 :(得分:1)
断言仅用于质量控制目的。删除它们不得改变程序的行为(即程序不能依赖断言来处理任何事情)。 如果发生的事情不应该发生,但在恶劣的情况下可能发生 - 例如网络连接丢失了。当失败也是一种选择时,使用返回值表示成功。
答案 7 :(得分:0)
简单的答案是两者,但第二个更重要。断言检查设计假设,因此在调用fn()之前我会有前置条件,例如给定资源可能可用。断言通常不会在发布代码中执行任何操作,但不一定如此。如果你的函数gn要求某些东西能够正确工作是很重要的,那么它就会使用if语句并返回错误代码,或抛出异常。断言通常在发布代码中不执行任何操作,因此在这种情况下,您的函数可能会崩溃。
另请参阅this question
的更详细答案答案 8 :(得分:0)
这实际上取决于语言/运行时环境以及错误的性质。
通常,程序无法从断言失败中恢复(即它会崩溃)。这可能是也可能不是你想要的。
如果您的环境支持异常,您也可以使用这些异常,如果您愿意,可以使用这些异常处理错误,如果您没有处理错误,将会中止一条有用的消息。
“返回false”是容易出错的(b / c人忘记检查返回值),所以只有在断言和异常都没有的情况下我才会使用它。
答案 9 :(得分:0)
取决于您要检查的内容。在第一种情况下,如果发生的坏事违反了您的类的合同,抛出一个对客户来说意味着什么的异常。返回false将不会让任何人知道状态是不正确的。
答案 10 :(得分:0)
我会在合同之类的东西被破坏时使用断言。这是什么意思:在数学中,没有定义除零。所以与分工功能的合同被打破了。有关合同的更多信息,请参阅埃及的演变语言。
在某些情况下,我会实现第二个具有默认值的附加参数的函数,并处理异常,如StrinToIntegerDef(string,default),当string不转换为Integer时返回默认值。
如果程序的正常执行没有受到威胁,可以返回false。
如果语言允许的话,我更喜欢有意义的异常,至少是形式断言(条件,消息)。
此外,如果有多种可能失败,请返回一些枚举值而不是false。
答案 11 :(得分:0)
使用断言来强制执行函数preconditions(如果函数具有任何含义,则必须保持为真的条件)。