作为参数传递时,隐式方法无法进行函数转换?

时间:2019-09-24 12:06:13

标签: 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

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

1 个答案:

答案 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中提供了有关此问题的更多技术细节。