我可能会丢失一些东西,但是遇到了一种意外地无法工作的模式。
在这里:
object A {
def bar(func: (Int, Int) => Int): Int = 2
def bar(func: Int => Int): Int = 3
def foo(func: Int => Int): Int = 4
}
def f(n: Int) : Int = n + 1
val g: Int => Int = f
A.foo(f) // works fine
A.bar(f) // doesn't work
A.bar(g) // but this works
编译器要求我显式应用方法f
以便通过它(编写f _
):
Unapplied methods are only converted to functions when a function type is expected.
我不明白为什么将f
传递给A.foo
而不是传递给A.bar
时隐式进行转换。 bar
有两个重载,但我不确定为什么吗?
我在Scala 2.12.8中使用了scalac。
答案 0 :(得分:11)
错误消息将您引向正确的方向:作为一种方法,f
并不直接等同于类型Int => Int
的值,即使它们相似。为了将其作为参数传递,f
需要转换为一个值,该值通常但并非总是隐式完成。
在声明val g = f _
或使用A.bar(f _)
时,您将方法显式转换为值。
由于bar
方法已重载,编译器不确定将f
转换为哪种类型(是Int => Int
还是(Int,Int) => Int
?)。为避免任何意外,它会要求您进行明确的转换。您还可以使用A.bar(f: Int => Int)
对其进行编译,因为通过显式选择bar
定义之一可以消除歧义。
编译器可能会尝试对此进行推理,因为您正在传递Int => Int
,并且仅当您打算将其赋予bar(Int => Int)
时,隐式method-> value提升才会发生,但是在这种情况下只是没有。可能有一个技术原因,例如编译器由于组合爆炸而没有尝试将重载分辨率与隐式提升结合在一起。我认为这是编译器的一个次要限制,可以通过更明确地避免它。更明确的往往更好!
如@slouc的评论所链接,here中提供了有关此问题的更多技术细节。