【问题标题】:Overriding trait method with default parameter使用默认参数覆盖 trait 方法
【发布时间】:2017-05-24 15:40:41
【问题描述】:

假设下面的例子——执行时返回——“fatherfather”

trait Action {
    def doSomething(s:String = "father") = s
}

class RevokeAction extends Action{
    override def doSomething(s:String) = {
        s + s
    }
}

object HelloWorld {
  def main(args: Array[String]): Unit = {
    val revokeAction = new RevokeAction()
    revokeAction.doSomething()
  }
}

查看编译器所做的事情 - 更好地解释正在发生的事情

package <empty> {
  abstract trait Action extends Object {
    def doSomething(s: String): String = s;
    <synthetic> def doSomething$default$1(): String = "father";
    def /*Action*/$init$(): Unit = {
      ()
    }
  };
  class RevokeAction extends Object with Action {
    <synthetic> def doSomething$default$1(): String = RevokeAction.super.doSomething$default$1();
    override def doSomething(s: String): String = s.+(s);
    def <init>(): RevokeAction = {
      RevokeAction.super.<init>();
      RevokeAction.super./*Action*/$init$();
      ()
    }
  };
  object HelloWorld extends Object {
    def main(args: Array[String]): Unit = {
      val revokeAction: RevokeAction = new RevokeAction();
      {
        revokeAction.doSomething(revokeAction.doSomething$default$1());
        ()
      }
    };
    def <init>(): HelloWorld.type = {
      HelloWorld.super.<init>();
      ()
    }
  }
}

能否详细说明为什么这是预期的行为?

【问题讨论】:

    标签: scala


    【解决方案1】:

    因为 Scala 规范说它应该是这样工作的。 Section 5.1.4 (Overriding):

    一个覆盖方法从 在超类中定义。 通过在 覆盖方法可以添加新的默认值(如果 超类中的相应参数没有默认值)或 覆盖超类的默认值(否则)。

    在内部,指导 JVM 的 Scala 实现必须将默认参数存储为声明类的成员,因为 JVM doesn't directly support default arguments on methods

    【讨论】:

    • 忽略了规范中的声明 - 谢谢!
    • “作为声明类的常量成员”我认为你的意思是方法。
    • @AlexeyRomanov “声明类”是指声明具有默认参数的方法的类。
    • @YuvalItzchakov 我的意思不是“常量”,而不是“类”。
    【解决方案2】:

    Scala中,默认参数,会创建一个默认字段来保持这个值,当你调用不带参数的方法时,编译器会自动设置默认参数 作为此方法的参数。喜欢:

    revokeAction.doSomething(revokeAction.doSomething$default$1());
    

    作为你的反编译代码,默认参数在Action类中设置:

    <synthetic> def doSomething$default$1(): String = "father";
    

    当您在没有parameter s 的情况下调用doSomething 方法时,它正在调用:

    revokeAction.doSomething(revokeAction.doSomething$default$1());
    

    带有默认参数revokeAction.doSomething$default$1(),因为RevokeAction不是overridedef doSomething$default$1(),所以默认参数仍然是father

    <synthetic> def doSomething$default$1(): String = RevokeAction.super.doSomething$default$1();
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-10-31
      • 2015-01-20
      • 1970-01-01
      • 2018-09-14
      • 2013-05-27
      • 2012-08-04
      • 2016-01-03
      • 1970-01-01
      相关资源
      最近更新 更多