编译器无法识别函数重载,因为类型被擦除.怎么克服这个?

Oll*_*liP 5 scala parametric-polymorphism

我有一个问题,下面的代码中名为fooSome的两个方法不能编译,因为编译器报告重复的方法名称有问题:

class Foo() {

  // variable block has 2 closure variables
  def fooSome(block: Some[(Int, String) => Unit]) = {

  }

  // variable block has 1 closure variables
  def fooSome(block: Some[Int => Unit]) = {

  }

  // variable block has 2 closure variables
  def fooNoSome(block: (Int, String) => Unit) = {

  }

  // variable block has 1 closure variables
  def fooNoSome(block: Int => Unit) = {

  }
}
Run Code Online (Sandbox Code Playgroud)

相反,编译器报告没有与名为fooNoSome的两个方法发生此类方法名称冲突.所以问题是编译器没有看到"Some [(Int,String)=> Unit]"和"Some [(Int)=> Unit]" 之间的区别,而"(Int,String)=> Unit" 对于fooNoSome方法,被视为与"(Int)=> Unit" 不同的签名.

我可以通过创建一个用于"Some [(Int,String)=> Unit]"案例的Some2Args类和用于"Some [(Int)=> Unit]"案例的Some1Arg类来解决这个问题.

我的问题是,是否有更优雅,更省力的解决方案.

Ale*_*nov 8

编译器确实看到它们之间的区别,它只是不允许超载使用这种差异(因为擦除Some[(Int, String) => Unit]Some[Int => Unit]是相同的,JVM不允许超载时的参数擦除是相同的).解决方案是添加伪隐式参数:

class Foo() {
  def fooSome(block: Some[(Int, String) => Unit]) = {

  }

  def fooSome(block: Some[Int => Unit])(implicit d: DummyImplicit) = {

  }
}
Run Code Online (Sandbox Code Playgroud)

还要注意,删除fooNoSomefooNoSome(Function2)fooNoSome(Function1),所以如果你想添加另一个带有一个或两个参数的函数的重载,你需要DummyImplicit再次使用这个技巧:

  def fooNoSome(block: Double => Unit)(implicit d: DummyImplicit) = ...
Run Code Online (Sandbox Code Playgroud)