Scala 方法类型和作为参数的方法
在下面的代码示例中,我不明白为什么函数 fun 可以作为参数传递给方法 addAction
。方法 fun
的类型为 Unit
,而方法 addAction
则需要一个类型为 () =>; 的函数。单位
。
如果 fun
的类型为 () =>; Unit
,那么当我尝试将 fun
添加到操作列表时,为什么编译器会抱怨 fun
的类型为 Unit
: actions = 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"
}
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
以此作为介绍性示例:
这两行都可以编译并且(由于类型推断)它们看起来是等效的。然而,
a1
的类型为Unit
,而a2
的类型为() =>单位
...这怎么可能?由于您没有显式提供
a1
类型,编译器会将fun
解释为Unit
类型的方法fun
调用,因此a1
的类型与fun
的类型相同。这也意味着该行将打印fun1执行。但是,
a2
已经显式声明了() =>;的类型。单位
。编译器在这里为您提供帮助,它理解因为上下文需要() => 类型的函数,所以编译器可以帮助您。 Unit
并且您提供了与该类型匹配的方法,它不应该调用该方法,而应将其视为第一类函数!您不一定要显式指定
a1
的类型。说:你现在明白你的问题出在哪里了吗?
Take this as an introductory example:
Both lines compile and (thanks to type inference) they look equivalent. However
a1
is of typeUnit
whilea2
is of type() => Unit
... How is this possible?Since you are not explicitly providing type of
a1
, compilers interpretsfun
as a methodfun
call of typeUnit
, hence the type ofa1
is the same as type offun
. It also means that this line will print fun1 executed.However,
a2
has explicitly declared type of() => Unit
. The compiler helps you here and it understands that since the context requires a function of type() => Unit
and you provided a method matching this type, it shouldn't call that method, but treat it as first class function!You are not doomed to specify type of
a1
explicitly. Saying:Do you now understand where your problem is?
在第一种情况下,您需要编写
fun _
以避免调用该方法并执行 eta 扩展。这将起作用:
如果您不这样做,则会评估
fun
。有关更多详细信息,请参阅 方法值) >Scala 语言参考。
至于为什么在第二种情况下
fun
没有被计算,这是因为类型推断可以清楚地得出addAction
需要一个函数。顺便说一句,fun
的类型从技术上讲是()Unit
,而不是Unit
,即方法类型,而不是值类型。有关详细信息,请参阅参考中的第 3.3.1 节。You need to write
fun _
in the first case to avoid calling the method and performing eta-expansion instead.This will work:
If you don't do this, then
fun
is evaluated.For more details, see Section 6.7 (Method Values) of the Scala Language Reference.
As to why
fun
is not evaluated in the second case, it is because type inference can clearly conclude thataddAction
expects a function. By the way, the type offun
is technically()Unit
, notUnit
, that is, a method type, and not a value type. See Section 3.3.1 in the reference for more.方法和功能之间存在差异。在您的情况下
actions
是一个函数列表。当编译器知道需要一个函数时(例如addAction
的情况),它可以自动将方法fun
转换为函数。现在::
也是一个方法,因此编译器也知道它接受函数作为参数。但问题在于右结合运算符::
的语法糖。如果您像方法一样调用它:actions.::(fun)
它将编译(尽管我目前无法测试它)。当编写fun :: actions
时,编译器认为fun
是一个表达式,因此对其求值,并且由于它“返回”一个Unit
你得到了你的编译器错误。编辑
由于我现在有可能检验我的假设(这是错误的),以下是您的选择:
There is a difference between methods and functions. In your case
actions
is a list of functions. When the compiler knows that a function is required (like in the case ofaddAction
) it can automatically convert a methodfun
into a function. Now::
is also a method, therefore the compiler also knows that it takes functions as parameters. But the problem is the syntactic sugar of the right-associative operator::
. If you were to call it like a method:actions.::(fun)
it will compile (although I can't test it at the moment). When writingfun :: actions
the compiler thinks thatfun
is an expression and therefore evaluates it and since it "returns" aUnit
you get your compiler error.EDIT
Since I now have the possibility to test my hypothesis (which was wrong) here are your options: