为什么以下不能在 Scala 中编译:
class A
class B
object X {
def f[Q <: A](q: Q): Q = q
def f[Q <: B](q: Q): Q = q
}
带有错误信息
<console>:16: error: method f is defined twice
conflicting symbols both originated in file '<console>'
def f[Q <: B](q: Q): Q = q
据我了解,类型删除后,
def f[Q <: A](q: Q): Q
应替换为其上限:def f(q: A): Any
第二个重载 f
相应地。所以它们在类型删除后应该是可区分的。那么为什么 Scala 会提示呢?
最佳答案
只是为了补充@chengpohi 的答案,您实际上可以使用类型类实现静态调度(重载是一种特殊情况):
trait A
trait B
implicit class RichA[Q <: A](q: Q){ def f = q }
implicit class RichB[Q <: B](q: Q){ def f = q }
scala> (new A{}).f
res0: A = $anon$1@39c1fe0b
scala> (new B{}).f
res1: B = $anon$1@20011bf
它不能自然工作的原因只是 Scala 必须模仿 Java 的重载(及其删除)以保持代码与外部 Java 代码和 Scala 的内部特性和保证兼容。在您的情况下(但并非总是如此)重载基本上是一个静态调用,因此可以在编译时进行处理,但 JVM 的
invokestatic
是否调度in runtime很遗憾:Before performing the method invokation, the class and the method identified by are resolved. See Chapter 9 for a description of how methods are resolved.
invokestatic looks at the descriptor given in , and determines how many arguments the method takes (this may be zero). It pops these arguments off the operand stack. Then it searches the list of static methods defined by the class, locating the method methodname with a descriptor descriptor.
所以,不管它知道
Q <: A
限制 - 它不知道 Q
的正式类型在运行时,所以一些像@chengpohi 指出的情况似乎无法检测或解决(实际上他们可以根据线性化的信息来做到这一点 - 唯一的缺点是运行时类型参与调度)。例如,Haskell 在编译时确定正确的方法(据我所知),因此类型类能够通过决定在编译时调用正确的方法来弥补真正静态调度的缺乏。
附言请注意,在 Haskell 中,重载用于动态调度(模式匹配)和用于静态调度的类,因此与 Java 相比,它基本上是相反的。
关于scala - 为什么重载具有不同上限的多态方法不能在 Scala 中编译,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43227416/