作为参数传递时,隐式函数转换方法不起作用?

kno*_*upe 7 scala

我可能会丢失一些东西,但是遇到了一种意外地无法工作的模式。
这里是:

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
Run Code Online (Sandbox Code Playgroud)

编译器要求我显式应用该方法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。

fra*_*isr 11

错误消息为您指明了正确的方向:作为方法,即使它们相似,f也不直接等于type的值Int => Int。为了将其作为参数传递,f需要将其转换为值,这通常但并非总是隐式完成。

声明val g = f _或使用时A.bar(f _),将方法显式转换为值。

由于该bar方法已重载,因此编译器不确定要转换f为哪种类型(是Int => Int还是(Int,Int) => Int?)。为避免任何意外,它会要求您进行明确的转换。您也可以使用进行编译A.bar(f: Int => Int),因为通过显式选择其中一个bar定义可以消除歧义。

编译器可能会尝试对此进行推理,因为您传递了a Int => Int,并且隐式method-> value提升仅在您打算将其提供给时才会发生bar(Int => Int),但在这种情况下则不会。可能有一个技术原因,例如编译器由于组合爆炸而没有尝试将重载分辨率与隐式提升结合在一起。我认为这是编译器的一个次要限制,可以通过更明确地避免它。更明确的往往更好!

如@slouc的评论中所链接,有关此问题的更多技术详细信息,请参见此处