对by-name参数传递的函数使用apply(“()”):不强制求值?

时间:2013-01-20 22:03:21

标签: scala callbyname

我有一个功能:

def nanoTime() = {
    println("Getting nano time...")
    System.nanoTime // returns nanoTime
}

和另一个函数,它带有一个函数

def printTime(time: => Long) = {  // indicates a by-name parameter
    println(">> delayed()")
    println("Param: " + time)
    time // returns time
}

现在就是这样。当我这样做时:

scala> printTime(nanoTime())
>> delayed()
Getting nano time...
Param: 546632085606127
Getting nano time...
res11: Long = 546632086131624

我得到的结果与我一样:

scala> printTime(nanoTime)
>> delayed()
Getting nano time...
Param: 546622367510997
Getting nano time...
res10: Long = 546622368149903

之间没有区别:

scala> printTime(nanoTime())

scala> printTime(nanoTime)

因此,传递函数名称并传递函数名称后跟()没有区别。总是这样,或者这个casE有什么特别之处?

感谢。

1 个答案:

答案 0 :(得分:8)

Scala具有参数列表的概念,其中方法可能需要多个参数列表。然而,为方便起见,它还允许省略终端空参数列表。所以

f
f()
f()()

可能都是一回事 - 在你看f之前你不知道。 by-name参数的作用是延迟代码块的执行。现在,正式如果我们有

def f0: String = "salmon"
def f1(): String = "herring"
def f2()(): String = "halibut"

然后,如果转换为函数,您可能希望f0匹配一个名字参数而其他参数不匹配。具体来说,你会期待

f0   <==>   => String
f1   <==>   () => String
f2   <==>   () => () => String
转换时

让我们看看通过f _请求时实际发生的事情:

scala> f0 _
res4: () => String = <function0>

scala> f1 _
res5: () => String = <function0>

scala> f2 _
res6: () => () => String = <function0>
好吧,好吧f0实际上转换为一个带有一个空参数块而不是零的函数(这是一个by-name参数的样子)。所以事实证明你的by-name参数根本没有将你的方法转换成函数 - 类型签名将不匹配!

相反,它的原因是这样的:

// I need a code block that returns a long
nanoTime             // Wait, there is no nanoTime exactly
nanoTime()           // Aha, that works!  Must have meant that
: => { nanoTime() }  // There, nicely packaged.

您认为没有区别的原因是,为了返回Long,by-name参数已经填充了缺少的(),但随后将整个事物包装在代码块中稍后执行。

(另请注意,名称参数实际只是Function0在幕后 - 即x: => A真的是x: () => A - 并且“零参数块”事物只是一个编译器小说。实际上,所有参数块都是编译器小说--JVM只知道一个参数列表。而且这是一个无块的小说,加上谁关心 - 关于-empty-parens小说,导致观察到的行为。)

如果从空参数块请求函数,那么事情就像这样:

def printF(f: () => String) = println(f())

scala> printF(f0)
<console>:23: error: type mismatch;
 found   : String
 required: () => String
              printF(f0)
                     ^

scala> printF(f1)
herring

scala> printF(f2)
<console>:23: error: type mismatch;
 found   : () => String
 required: String
              printF(f2)

scala> printF(f2())
halibut

现在parens 很重要,因为编译器正在尝试将方法签名与函数签名匹配。副名参数情况的特殊情况不再适用。