scala:覆盖命名参数

时间:2016-05-23 03:16:57

标签: scala

鉴于以下代码

class Parent {
  def mth(p1: Int = 1, p2: Int = 2) = p1 + p2
}
class Child extends Parent{
  override def mth(p2: Int = 10, p1: Int = 20) = super.mth(p2, p1)
}
object Main {
  def main(args: String[]) = {
    val parentRefToChild: Parent = new Child
    println(parentRefToChild.mth(p1=1))   // 21
  }
}

输出为21,但我认为它应该是11。在检查已编译的.class文件时,我发现parentRefToChild.mth(p1=1)已编译为parentRefToChild.mth(1, parentRefToChild.mth$default$2())。 scala编译器如何以这种方式运行。

1 个答案:

答案 0 :(得分:5)

问题在于您更改了Child中的参数序列:

override def mth(p2: Int = 10 , p1: Int = 20)

因此,在mth类中为Child生成的合成方法将类似于:

def mth$default$1 = 10 // generated method for p2 in Child
def mth$default$2 = 20 // generated method for p1 in Child

当您在mth类引用上调用Parent时,静态类型检查用于确定参数是否具有默认值。此处,静态类型检查将在Parent上完成,parentRefToChild类型为Parent

因此,当遇到parentRefToChild.mth(p1=1)时,编译器知道parentRefToChild实际上正在持有Child类实例。它只是尝试匹配来自mth类的Parent签名。现在,它在此处看到p1的值已提供但p2缺失并且具有默认值,它只是将parentRefToChild.mth(p1=1)替换为:

parentRefToChild.mth(1, parentRefToChild.mth$default$2())

现在,在运行时,合成方法mth$default$2()Child类中选取(parentRefToChild保存Child的实例),然后变为:

parentRefToChild.mth(1, 20)

因此,您获得21作为输出。