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

dub*_*ech 3 scala callbyname

我有一个功能:

def nanoTime() = {
    println("Getting nano time...")
    System.nanoTime // returns nanoTime
}
Run Code Online (Sandbox Code Playgroud)

和另一个功能,它需要一个功能

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

现在就是这样的.当我做:

scala> printTime(nanoTime())
>> delayed()
Getting nano time...
Param: 546632085606127
Getting nano time...
res11: Long = 546632086131624
Run Code Online (Sandbox Code Playgroud)

当我这样做时,我得到了相同的结果:

scala> printTime(nanoTime)
>> delayed()
Getting nano time...
Param: 546622367510997
Getting nano time...
res10: Long = 546622368149903
Run Code Online (Sandbox Code Playgroud)

之间没有区别:

scala> printTime(nanoTime())
Run Code Online (Sandbox Code Playgroud)

scala> printTime(nanoTime)
Run Code Online (Sandbox Code Playgroud)

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

谢谢.

Rex*_*err 8

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

f
f()
f()()
Run Code Online (Sandbox Code Playgroud)

可能都是同一件事 - 直到你看,你才知道f.by-name参数的作用是延迟代码块的执行.现在,正式如果我们有

def f0: String = "salmon"
def f1(): String = "herring"
def f2()(): String = "halibut"
Run Code Online (Sandbox Code Playgroud)

f0如果转换为函数,那么你希望匹配一个名字参数而不是其他参数.具体来说,你会期望

f0   <==>   => String
f1   <==>   () => String
f2   <==>   () => () => String
Run Code Online (Sandbox Code Playgroud)

转换时.让我们看看在请求时实际发生了什么f _:

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

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

scala> f2 _
res6: () => () => String = <function0>
Run Code Online (Sandbox Code Playgroud)

那好吧; 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.
Run Code Online (Sandbox Code Playgroud)

你没有看到区别的原因是,为了返回a Long,by-name参数已经填充了缺失(),但随后将整个事物包装在代码块中以便稍后执行.

(另请注意,名字参数实际上只是Function0在幕后 - 也就是说,x: => A实际上x: () => A- 并且"零参数块"的东西只是一个编译器小说.实际上,所有参数块都是编译器小说--JVM只知道一个单一的参数列表.正是这种无块的小说,再加上那些关心空洞的小说,导致观察到的行为.)

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

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
Run Code Online (Sandbox Code Playgroud)

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