scala - 为什么重载具有不同上限的多态方法不能在 Scala 中编译

标签 scala overloading type-erasure

为什么以下不能在 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/

相关文章:

c++ - 派生类中的虚函数没有重载

用于模式匹配的 Scala 类型删除

scala - 对于我的下一个项目,一个网络应用程序,应该使用 scala+wicket 还是 scala+lift?

scala - Spark SQL 在 scala 中执行

java - 在不重载的情况下组合 Java 函数

Java 8 Hibernate Streams 标准分组按删除类型?

java - 当 ArrayList 都是通用类型时,为什么我无法通过 addAll 方法将 ArrayList 的内容添加到另一个 ArrayList 中?

Scala-IDE - 具有不同签名的对象 `apply` 方法混合使用了吗?

scala - 如何进行与硬件无关的并行编程?

java - 为什么这不是重载?