姓名呼叫:=>类型
该=> Type
符号代表按名称调用,这是可以传递参数的多种方式之一。如果您不熟悉它们,我建议您花一些时间阅读该Wikipedia文章,即使现在它主要是按值调用和按引用调用。
这意味着将传递的内容替换为函数内部的值名称。例如,使用以下功能:
def f(x: => Int) = x * x
如果我这样称呼它
var y = 0
f { y += 1; y }
然后代码将像这样执行
{ y += 1; y } * { y += 1; y }
虽然这提出了标识符名称冲突的情况。在传统的按名称呼叫中,发生了一种称为捕获避免替换的机制来避免名称冲突。但是,在Scala中,这是通过另一种方式实现的,结果是相同的-参数内的标识符名称无法引用,或者被调用函数中的影子标识符。
在解释其他两点之后,我还会谈到与按名字呼叫有关的其他几点。
0-arity函数:()=>类型
语法() => Type
代表的类型Function0
。也就是说,一个不带任何参数并返回某些内容的函数。这就相当于调用该方法size()
-它不带任何参数并返回一个数字。
但是,有趣的是,此语法与匿名函数文字的语法非常相似,这是造成混淆的原因。例如,
() => println("I'm an anonymous function")
是值为0的匿名函数文字,其类型为
() => Unit
所以我们可以这样写:
val f: () => Unit = () => println("I'm an anonymous function")
但是,重要的是不要将类型与值混淆。
单位=>类型
这实际上只是一个Function1
,其第一个参数是type Unit
。编写它的其他方式是(Unit) => Type
或Function1[Unit, Type]
。问题是……这不可能永远是人们想要的。该Unit
类型的主要目的是指示一个不感兴趣的值,因此接收该值没有任何意义。
例如,考虑
def f(x: Unit) = ...
一个人可能怎么办x
?它只能有一个值,因此不需要接收它。一种可能的用途是链接函数返回Unit
:
val f = (x: Unit) => println("I'm f")
val g = (x: Unit) => println("I'm g")
val h = f andThen g
因为andThen
仅在上定义Function1
,并且要链接的函数返回Unit
,所以我们必须将它们定义为Function1[Unit, Unit]
能够链接它们的类型。
混乱的根源
造成混淆的第一个原因是认为0 arity函数存在的类型和文字之间的相似性也存在于按名称调用中。换句话说,因为
() => { println("Hi!") }
是的字面量() => Unit
,然后
{ println("Hi!") }
将是一个字面意思=> Unit
。它不是。那是一段代码,而不是文字。
另一个造成混淆的原因是Unit
类型的值被写入()
,看起来像一个0参量的参数列表(但事实并非如此)。
case class Scheduled(time: Int)(callback: => Unit)
。这是可行的,因为辅助参数列表未公开公开,也未包含在生成的equals
/hashCode
方法中。