为什么这个函数重载会在Scala中产生编译错误?

时间:2015-11-24 12:19:00

标签: scala overloading

是什么导致以下代码在Scala 2.11中产生编译错误?

class Foo {
  def fn(a: Seq[Int], b: Int => Int) {}

  // Comment this line out
  def fn(a: Map[String, String], c: String => Double) {}
}

object Bar {
  def main(args: Array[String]) {
    val f = new Foo()
    f.fn(Seq(1, 2), _ * 2)
  }
}

错误:

Error:(9, 21) missing parameter type for expanded function ((x$1) => x$1.$times(2))
    f.fn(Seq(1, 2), _ * 2)
                    ^

但是,如果Map[String, String], String => Double fn版本的file.exists() 被注释掉,代码就会编译。我可以通过给编译器提供一两个提示来轻松解决这个问题,但我不想在Scala中明确指定类型: - )

(旁白:我知道method overloading is frowned on in Scala

2 个答案:

答案 0 :(得分:3)

您为编译器创建了某种“鸡和蛋”问题:

  1. 要选择重载,编译器需要知道所有参数的完整类型。
  2. 要获得调用中函数参数的完整类型,编译器需要推断其参数的类型。
  3. 要推断此参数的类型,它需要返回1.并选择一个重载(*的右侧不足以进行类型推断,因为{{1}本身可能会超载自己)。
  4. 编译器无法突破这个圈子,因而无法解决问题。你必须向编译器显示门:

    • 如果指定了你解决的lambda参数的类型2.并使编译器能够推断出正确的函数类型,从而选择适当的重载。
    • 如果您使用curried函数 - 如另一个答案中所建议的那样 - 您解决1.并帮助编译器根据第一个参数选择适当的重载,以便随后可以推断出第二个参数的类型。

答案 1 :(得分:2)

我认为编译器无法确定选择哪个重载,因为函数的类型未完全指定。在类型推断中辅助scala编译器的一种常用方法是使用多个参数块,例如:

class Foo {
  def fn(a: Seq[Int])(b: Int => Int) {}
  def fn(a: Map[String, String])(c: String => Double) {}
}

object Bar extends App {
  val f = new Foo()
  f.fn(Seq(1, 2))(_ * 2) // this works because the overload is chosen based on the first parameter list
}

如果您不想这样做,则必须更明确地指定函数的类型,如下所示:

f.fn(Seq(1,2), (x: Int) => x * 2)