为什么Scala的predef中的require方法允许String作为参数?

时间:2012-05-20 11:39:17

标签: scala

我可以在Scala的Predef类中使用String作为第二个参数,例如,

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

首先考虑将require方法作为第二个参数重载为不同的参数。但事实并非如此。 require方法的签名(Scala 2.9.1)是:

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

为什么上述方法调用可能?

4 个答案:

答案 0 :(得分:21)

我不完全理解这个问题,但这里有一点解释。 requirePredef中有一个重载版本:

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不等于Int,则会将4(类型为Any)的实际值添加到错误消息中。这就是选择: =>的原因 - 允许任意值。

require(list.isEmpty, list.size) 部分怎么样?这称为按名称调用,基本上意味着:在访问时评估此参数。想象一下以下片段:

list

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

答案 1 :(得分:3)

require方法在scala具有默认参数(在2.8中引入)之前存在于Predef中,因此如果您想要给定参数的默认行为,则重载是唯一的选项。如消息所示,第二个参数可以是任何内容,然后将其用作抛出message的{​​{1}}(通过调用其toString方法),( if < / em>它被抛出 - 即如果要求失败)。

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

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

答案 2 :(得分:2)

  

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

签名没有说明。签名表示第二个参数是类型Any ,并且此参数是按名称传递

“by name”由前缀=>符号表示,该符号 not mean函数 - 函数始终表示为输入参数 =&gt ; 结果类型Function0() => type

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

答案 3 :(得分:-1)

答案很简单:你期待

的第二个参数
require(boolean: Boolean, message: => Any): Unit

成为任何功能并询问为什么String有效,即使它不是功能。< / p>

将其细分为:固定的String只不过是功能

  1. 不接受任何论据
  2. 不需要调用()个括号
  3. 在每次通话中产生相同的结果
  4. 实际上,以下两个语句在Scala中是等效的:

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

    因此,您可能会说=> Any符合String