3

我有一个功能:

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)

所以传递函数名和传递函数名后跟()是没有区别的。是不是一直都是这样,还是这个案子有什么特别之处?

谢谢。

4

1 回答 1

8

Scala 有参数列表的概念,其中一个方法可能需要多个参数。但是,为了方便起见,它也允许省略终端空参数列表。所以

f
f()
f()()

可能都是一样的——你不知道,直到你看f. 别名参数的作用是延迟代码块的执行。现在,正式地,如果我们有

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 参数根本没有将你的方法转换为函数——类型签名不匹配!

因此,它的原因如下:

// 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.

您看不到区别的原因是,为了返回 a Long, by-name 参数已经填充了缺失的(),然后将整个内容包装在代码块中以供稍后执行。

(还要注意,名称参数实际上只是Function0在幕后——也就是说,x: => A真的是x: () => A——而“零参数块”只是编译器虚构的。实际上,所有参数块都是编译器虚构的——JVM只知道一个参数列表。正是这种无块虚构,加上 who-cares-about-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

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

于 2013-01-20T22:33:02.507 回答