Man*_*anu 6 methods scala anonymous-function
在下面的代码示例中,我不明白为什么函数fun可以作为参数传递给方法addAction.该方法fun属于类型Unit,而该方法addAction需要类型的函数() => Unit.
如果fun是类型() => Unit,那么当我尝试添加到操作列表时,为什么编译器会抱怨fun类型?Unitfunactions = fun :: actions
package myscala
object MyScala {
def fun() { println("fun1 executed.") }
def addAction(a: () => Unit) {
actions = a :: actions
}
var actions: List[() => Unit] = List()
def main(args: Array[String]) {
// the following line would produce a compiler error (found: Unit, required: () => Unit), it's OK
// actions = fun :: actions
actions = (() => fun) :: actions // OK
// I would expect the same compiler error here (found: Unit, required: () => Unit), but it's OK why?
addAction(fun)
actions.foreach(_()) // prints twice "fun1 executed"
}
}
Run Code Online (Sandbox Code Playgroud)
以此作为介绍性示例:
def fun() { println("fun1 executed.") }
val a1 = fun
val a2: () => Unit = fun
Run Code Online (Sandbox Code Playgroud)
这两行编译和(由于类型推断)它们看起来相同.不过a1是类型Unit,而a2类型是() => Unit...这怎么可能?
由于您没有明确提供类型a1,因此编译器解释fun为fun类型的方法调用Unit,因此类型a1与类型相同fun.这也意味着这一行将打印fun1执行.
但是,a2已经明确声明了类型() => Unit.编译器在这里帮助你,它理解由于上下文需要一个类型的函数,() => Unit你提供了一个匹配这种类型的方法,它不应该调用该方法,而是将其视为一流函数!
您并不注定要明确指定类型a1.他说:
val a1 = fun _
Run Code Online (Sandbox Code Playgroud)
你现在明白你的问题在哪里吗?
您需要fun _在第一种情况下编写,以避免调用该方法并执行eta-expansion.
这将有效:
actions = (fun _) :: actions
Run Code Online (Sandbox Code Playgroud)
如果不这样做,则fun进行评估.
有关更多详细信息,请参见Scala语言参考的第6.7节(方法值).
至于为什么fun不在第二种情况下进行评估,这是因为类型推断可以清楚地得出结论,addAction期望一个函数.顺便说一下,类型fun是技术上的()Unit,而不是Unit方法类型,而不是值类型.请参阅第3.3.1节参考更多.