6

I can the require method in Scala's Predef class with a String as second argument, e.g.

require ("foo" == "bar", "foobar")

First a thought the require method is overloaded for different parameters as second argument. But it is not. The Signature of the require method (Scala 2.9.1) is:

require(requirement: Boolean, message: ⇒ Any): Unit

Why is the above method call possible ?

4

4 回答 4

22

我不完全理解这个问题,但这里有一些解释。require有一个重载版本Predef

def require(requirement: Boolean) //...
def require(requirement: Boolean, message: => Any) //...

由于message: => Any类型,第二个有点令人困惑。如果它只是简单的可能会更容易:

def require(requirement: Boolean, message: Any) //...

第二个参数当然是一条消息,如果不满足断言,则假定将其附加到错误消息中。你可以想象message应该是String类型,但Any你可以简单地写:

require(x == 4, x)

如果不等于 ,则将x(类型)的实际值添加到错误消息中。这就是为什么选择 - 允许任意值。Int4Any

但是: =>部分呢?这称为按名称调用,基本上意味着:在访问此参数时对其进行评估。想象以下片段:

require(list.isEmpty, list.size)

在这种情况下,您要确保list为空 - 如果不是,请将实际list大小添加到错误消息中。然而,使用正常的调用约定,list.size必须在调用方法之前评估该部分- 这可能是浪费的。使用按名称调用约定,list.size仅在第一次使用时评估 - 当错误消息是构造函数时(如果需要)。

于 2012-05-20T11:50:23.600 回答
4

require方法存在于Predefscala 具有默认参数(在 2.8 中引入)之前,因此如果您想要给定参数的默认行为,重载是唯一的选择。如消息所示,第二个参数可以是任何东西,然后将其用作message(通过调用其toString方法)所抛出的IllegalArgumentException,(如果它被抛出 - 即如果要求失败)。

请注意,参数实际上是按名称调用;也就是说,它被声明为=> Any,这意味着它只有在需求失败时才会被评估

这会以创建对象的形式造成性能损失,但在构建消息的成本很高的情况下(可能需要对数据结构进行一些 O(n) 访问),它可能很有用。

于 2012-05-20T11:49:36.360 回答
2

问题是,为什么 String 是第二个参数的有效类型,而签名说它必须是 function message: => Any

签名没有这样说。签名说第二个参数是类型的Any,并且这个参数是按名称传递的

“按名称”由前缀=>符号表示,但并不表示函数——函数始终表示为输入参数=>结果类型,并带有Function0being () => type

查找参数“按值”和“按名称”。

于 2012-05-21T01:42:09.340 回答
-1

答案很简单:你期望第二个参数

require(boolean: Boolean, message: => Any): Unit

成为Any的Function并询问为什么 a有效,即使它不是FunctionString

将其分解为:fixedString只不过是一个Function

  1. 不接受任何论据
  2. 不需要()调用括号
  3. 在每次调用中产生相同的结果

事实上,以下两个语句在 Scala 中是等价的:

def x: String = "ABC" // const value, even though 'def' implies a function
val x: String = "ABC"

所以你可能会说=> Any满足 a String

于 2012-05-20T12:03:27.133 回答