Scala 编译器无法识别函数重载,因为类型已被擦除。如何克服这个问题?

Scala 编译器无法识别函数重载,因为类型已被擦除。如何克服这个问题?,scala,parametric-polymorphism,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 =&g

我有一个问题,下面代码中名为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) = {

  }
}
相反,编译器报告没有这种方法名与名为fooNoSome的两个方法冲突。所以问题是编译器没有看到“Some[(Int,String)=>Unit]”和“Some[(Int)=>Unit]”之间的区别,而对于foonsome方法,“(Int,String)=>Unit”被视为与“(Int)=>Unit”不同的签名

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


我的问题是是否有一个更优雅、更省力的解决方案。

编译器确实看到了它们之间的区别,只是不允许在重载中使用这种区别(因为删除
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) = {

  }
}
还要注意的是,
foonsome
的擦除是
foonsome(Function2)
foonsome(Function1)
,因此如果您想添加另一个重载,该重载包含一个或两个参数的函数,您需要再次使用
DummyImplicit
技巧:

  def fooNoSome(block: Double => Unit)(implicit d: DummyImplicit) = ...

一个更系统的方法,没有虚拟的隐含,应该是这样的:

class Foo() {
  def fooSome[X](block: Some[X])(implicit cfs: CanFooSome[X]) = {
    cfs.handleThat(block)
  }
}

trait CanFooSome[X] {
  def handleThat(block: Some[X]): Unit // or other return type
}

// in carefully chosen scope for implicits
implicit object CanFooSomeIntToUnit extends CanFooSome[Int => Unit] {
  def handleThat(block: Some[Int => Unit]) = ...
}

// same for all other type combinations, like (Int, String) => Unit etc.
这是因为Scala编译器在编译时决定插入什么
对于CanFooSome实现,JVM在运行时看不到这方面的任何内容。此模式可能具有某些优势(例如可扩展性:可以从外部提供新的CanFooSome,而不会更改Foo的代码),并且不会随着fooSome类型数量的增加而变得更加混乱。

可能重复@om nom nom重载和擦除的问题与匹配和擦除不同,这个问题和答案都不是关于超载的。如果以前没有人问过这样的问题,我会很惊讶,但我在快速搜索中找不到重复的问题。谢谢你的回答,亚历克西。认为这解决了我的问题。