=>,()=>和Unit =>之间有什么区别
我试图表示一个函数,不接受任何参数,并返回没有价值(我正在模拟JavaScript中的setTimeout函数,如果你必须知道。)
case class Scheduled(time : Int, callback : => Unit)
不会编译,说“`val'参数可能不是名称调用”
case class Scheduled(time : Int, callback : () => Unit)
编译,但必须奇怪地调用,而不是
Scheduled(40, { println("x") } )
我必须这样做
Scheduled(40, { () => println("x") } )
什么也工作是
class Scheduled(time : Int, callback : Unit => Unit)
而是以一种不那么明智的方式进行调用
Scheduled(40, { x : Unit => println("x") } )
(什么是一个variables的types单元?)我想要的当然是一个构造函数,可以调用的方式,我会调用它,如果它是一个普通的函数:
Scheduled(40, println("x") )
给宝宝给他的瓶子!
按名称呼叫:=>types
=> Type
符号表示按名称调用,这是parameter passing的许多方法之一。 如果你不熟悉它们,我build议花一些时间阅读维基百科的文章,尽pipe现在它主要是通过价值和通过引用来调用。
这意味着什么是通过replace函数内的值名称。 例如,采取这个function:
def f(x: => Int) = x * x
如果我这样称呼它
var y = 0 f { y += 1; y }
然后代码将执行像这样
{ y += 1; y } * { y += 1; y }
虽然这提出了如果有标识符名称冲突会发生什么点。 在传统的call-by-name中,一个叫做capture-avoid的机制发生了,以避免名字冲突。 然而,在Scala中,这是以另一种方式实现的,具有相同的结果 – 参数中的标识符名称无法引用被调用函数中的影子标识符或影子标识符。
还有一些与名字相关的问题,我会在解释其他两个问题之后再说。
0-arity函数:()=>types
语法() => Type
表示Function0
的types。 也就是说,一个不带参数并返回一些东西的函数。 这相当于调用方法size()
– 它不带参数并返回一个数字。
然而,有趣的是,这个语法与匿名函数文本的语法非常相似,这是导致一些混淆的原因。 例如,
() => println("I'm an anonymous function")
是arity 0的匿名函数字面量,其types是
() => Unit
所以我们可以写:
val f: () => Unit = () => println("I'm an anonymous function")
但是,重要的是不要将types与价值混淆。
单位=>types
这实际上只是一个Function1
,其第一个参数是Unit
types。 其他写入方法是(Unit) => Type
或Function1[Unit, Type]
。 事情是……这不太可能是人们想要的。 Unit
types的主要目的是表示一个人不感兴趣的价值,所以没有意义接收这个价值。
考虑一下,例如,
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]
types以便链接它们。
混乱的来源
混淆的第一个来源是认为0-arity函数存在的types和文字之间的相似性对于名称也存在。 换句话说,这是因为
() => { println("Hi!") }
是一个字面值() => Unit
,然后
{ println("Hi!") }
将是一个字面=> Unit
。 不是这样。 这是一个代码块 ,而不是文字。
混淆的另一个来源是Unit
types的值被写成()
,它看起来像一个0-arity参数列表(但它不是)。
case class Scheduled(time : Int, callback : => Unit)
case
修饰符使构造函数的每个参数都有一个隐式的val
。 因此(正如某人指出的那样),如果你删除了case
你可以使用一个名字叫做参数。 编译器也许可以允许它,但是如果它创build了val callback
而不是变成lazy val callback
,可能会让人惊讶。
当你改变callback: () => Unit
现在你的情况只是一个函数,而不是一个名称的参数。 很明显,函数可以存储在val callback
所以没有问题。
最简单的方法来获得你想要的( Scheduled(40, println("x") )
使用call-by-name参数来传递一个lambda)可能会跳过这个case
并明确地创build一个apply
,首先得到:
class Scheduled(val time: Int, val callback: () => Unit) { def doit = callback() } object Scheduled { def apply(time: Int, callback: => Unit) = new Scheduled(time, { () => callback }) }
正在使用:
scala> Scheduled(1234, println("x")) res0: Scheduled = Scheduled@5eb10190 scala> Scheduled(1234, println("x")).doit x