在scala中,在require和assert之间选择什么

在scala中,在require和assert之间选择什么,scala,Scala,require和assert都用于在运行时执行某些检查,以验证某些条件 那么它们之间的基本区别是什么呢 我唯一看到的是requirethrowsIllegalArgumentException和assertthrowsAssertionError 如何选择使用哪一种?这只是我的主观观点 每当我想要对参数进行约束时,我就使用require 以自然数的阶乘为例。由于我们不想处理负数,我们想抛出一个IllegalArgumentException 只要您想确保某些条件(如不变量)在执行过程中始终为真,

require
assert
都用于在运行时执行某些检查,以验证某些条件

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

我唯一看到的是
require
throws
IllegalArgumentException
assert
throws
AssertionError


如何选择使用哪一种?

这只是我的主观观点

每当我想要对参数进行约束时,我就使用
require

以自然数的阶乘为例。由于我们不想处理负数,我们想抛出一个
IllegalArgumentException

只要您想确保某些条件(如不变量)在执行过程中始终为真,我就会使用
断言
。我认为这是一种测试方式

下面是一个带有
require
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)
}
result>1
为真时,循环至少执行一次。因此结果必须大于或等于
k
。这将是一个循环不变量

当您确定代码是正确的时,可以删除
断言
,但
要求
将保留。

如前所述,存在语义差异

  • assert表示程序已达到不一致的状态这可能是当前方法/函数的问题(我喜欢将其视为HTTP 500 InternalServerError)
  • require意味着方法的调用方出错,应该修复它的调用(我喜欢把它看作HTTP 400 BADDREQUEST)
还有一个主要的技术区别:

assert
@eliable(ASSERTION)
这意味着您可以使用断言下方的
-Xelide
-xdisableassertions
编译程序,编译器不会为断言生成字节码。如果有大量断言,这可以显著减少字节码大小并提高性能

知道了这一点,您可以使用
断言
来验证程序中的所有不变量无处不在(每个方法/函数调用的所有先决条件/后决条件),而不必在生产过程中付出代价

您通常会在启用所有断言的情况下进行“测试”构建,速度会慢一些,因为它会始终验证所有断言,然后您可以在没有断言的情况下进行产品的“生产”构建,这将消除通过断言进行的所有内部状态检查


require
是不可删除的,在库(包括内部库)中使用它可以更好地通知调用方调用给定方法/函数的先决条件。

用非常简单的语言:

Require
用于对函数的调用者或某个类的对象的创建者强制执行前提条件。而,
assert
用于检查函数本身的代码。
因此,如果先决条件失败,则会出现
非法参数异常
。然而,如果断言失败,并且不是调用方的错误,因此会出现
断言错误

require,则确保和不变性是契约式设计(CBD)开发过程中的概念

需要检查调用方在使用例程时应满足的前提条件

确保检查返回值的正确性(并验证仅发生了所需的更改,仅此而已)

不变性检查类在所有关键时刻的有效性

CBD是一种构建正确/健壮软件的开发方法。有关CBD的更多详细信息,请点击谷歌和埃菲尔软件的链接。希望这能有所帮助。

您可以查看Scala语言中的详细讨论

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

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

软件测试确保代码的通用性足以支持易出错的操作,并且不会被误用按合同设计控制代码不具有此类功能。换句话说,软件测试是纠正性的,合同设计是预防性的

  • assert
    用于编写单元测试,也就是说,如果一个方法通过了由
    assert
    表达式编写的所有测试,则该代码被认定为无错误。因此,
    assert
    位于操作代码之外,是一个独立的机构
  • require
    嵌入在代码中,并作为代码的一部分,以确保不会发生有害的事情

    • Scaladocs/javadocs也很不错:

      • 断言()
      测试表达式,如果为false,则抛出断言错误。如果下面的-Xelide大于断言,则不会生成对此方法的调用。

      • 需要()
      测试表达式,如果为false,则抛出IllegalArgumentException。此方法类似于assert,但将其归咎于t的调用方