在scala中要求和断言之间做什么选择

Ros*_*han 47 scala

二者requireassert用于在运行时期间执行某些检查,以验证某些条件.

那么它们之间的基本区别是什么?

我看到的唯一一个是require投掷IllegalArgumentExceptionassert投掷AssertionError.

如何选择使用哪一个?

Jea*_*ean 72

正如Kigyo所说,存在语义差异

  • assert意味着你的程序已达到一个不一致的状态,这可能是当前方法/函数的一个问题(我喜欢把它想象为HTTP 500 InternalServerError)
  • require意味着方法的调用者有错并且应该修复它的调用(我喜欢将它想象为HTTP 400 BadRequest)

还有一个主要的技术差异:

assert注释的@elidable(ASSERTION) 意思是您可以使用-Xelide-below ASSERTION或编译程序, -Xdisable-assertions编译器不会生成断言的字节码.如果您有大量断言,这可以显着减少字节码大小并提高性能.

知道了这一点,你可以使用assert来验证一切的不变量无处不在您的程序(每个单独的方法/函数调用的所有前提条件/后置),并没有付出代价的生产.

你通常会在启用所有断言的情况下进行" 测试 "构建,因为它会在任何时候验证所有断言都会变慢,然后你可以在没有断言的情况下进行产品的" 生产 "构建,这样你就可以消除通过断言完成所有内部状态检查

require 如果不是elidable,在库(包括内部库)中使用更有意义来通知调用者调用给定方法/函数的前提条件.


Kig*_*gyo 21

这只是我的主观观点.

require每当我想要参数约束时我都会使用.

作为一个例子,我们可以采用自然数的阶乘.由于我们不想解决负数,我们想要抛出一个IllegalArgumentException.

我会使用assert,只要你想确保某些条件(如不变量)在执行期间始终为真.我认为这是一种测试方式.

以下是使用require和的factorial的示例实现assert

def fac(i: Int) = {
  require(i >= 0, "i must be non negative") //this is for correct input

  @tailrec def loop(k: Int, result: Long = 1): Long = {
    assert(result == 1 || result >= k)   //this is only for verification

    if(k > 0) loop(k - 1, result * k) else result
  }

  loop(i)
}
Run Code Online (Sandbox Code Playgroud)

如果result > 1为true,则循环至少执行一次.所以结果必须大于或等于k.这将是一个循环不变量.

当你确定你的代码是正确的,你可以删除assert,但require会留下.


shv*_*abi 6

您可以在此处查看Scala 语言的详细讨论。

我可以补充一点,区分require和的关键assert是理解这两者。这两个都是软件质量工具,但来自不同范式的不同工具箱。总之assert软件测试工具采用纠正方法,而require合同设计工具采用预防方法。

require都是assert控制状态有效性的手段。历史上有两种不同的范式来处理无效状态。第一个是主流,统称为软件测试学科方法和工具。另一种称为合同设计。这是两个没有可比性的范式。

软件测试确保代码具有足够的通用性,能够执行容易出错的操作,并且不会被滥用。通过契约设计控制代码不具备这种能力。换句话说,软件测试是纠正性的,而契约设计是预防性的。

  • assert用于编写单元测试,即如果一个方法通过了表达式编写的所有测试assert,则该代码被认为是无错误的。所以assert席位除了运营代码之外,而且是一个独立的机构。
  • require嵌入到代码及其一部分中,以确保不会发生任何有害的情况。