在scala中覆盖惰性val的堆栈溢出

时间:2014-08-19 18:34:53

标签: scala scala-2.9

我已将代码修改为以下内容。我很困惑,为什么我在两个过滤器方法之间出现堆栈溢出(一个在我的特征中,一个在我的超类中)

object TestingOutTraits {

  val TestHandler = new Object with MySuper with MyTrait {
    override lazy val createdFilter = {
      "second part"
    }
  }

  def main(args: Array[String]) = {
    val result : String = TestHandler.start()
    System.out.println("result="+result)
  }
}

trait MySuper {

  protected def filter: String = {
    "first part to->"
  }

  def start() = {
    filter
  }
}

trait MyTrait { self: MySuper =>

  lazy val createdFilter = {
    "override this"
  }

  protected override def filter: String = {
    self.filter + createdFilter
  }
}

这是scala 2.9。任何想法在这里发生了什么?

编辑: 堆栈跟踪对于它如何来回跳转没有任何意义(我应该把它包含在原始帖子中)......

at MyTrait$class.filter(TestingOutTraits.scala:34)
at TestingOutTraits$$anon$1.filter(TestingOutTraits.scala:4)
at MyTrait$class.filter(TestingOutTraits.scala:34)
at TestingOutTraits$$anon$1.filter(TestingOutTraits.scala:4)

感谢, 迪安

3 个答案:

答案 0 :(得分:3)

self.filter中的调用MyTrait.filter会调用自身,从而导致无限递归,从而导致堆栈崩溃。

相反,MyTrait延长MySuper,并使用super.filter

trait MyTrait extends MySuper {
  lazy val createdFilter = {
    "override this"
  }

  protected override def filter: String = {
    super.filter + createdFilter
  }
}

答案 1 :(得分:1)

可替换地,

trait MySuper extends Filtered {

  protected def filter: String = {
    "first part to->"
  }

  def start() = {
    filter
  }
}

trait Filtered {
  protected def filter: String
}
trait MyTrait extends Filtered {

  lazy val createdFilter = {
    "override this"
  }

  protected abstract override def filter: String = {
    super.filter + createdFilter
  }
}

然后

  val nope = new MyTrait { }  // correctly DNC

和OP

  val TestHandler = new MySuper with MyTrait {
    override lazy val createdFilter = {
      "second part"
    }
  }

http://www.artima.com/pins1ed/traits.html#12.5

答案 2 :(得分:0)

嗯,我知道为什么无限递归虽然这似乎是scala中的线性化错误,但我不知道如何解决它:(。

嗯,所以事实证明编译器出于某种原因在我的新对象中粘贴了一个过滤器方法。我发现这与print:mixin on scalac就像这样

    $ scalac -Xprint:mixin TestingOutTraits.scala
      [[syntax trees at end of mixin]]// Scala source: TestingOutTraits.scala
    package <empty> {
      final object TestingOutTraits extends java.lang.Object with ScalaObject {
        private[this] val TestHandler: MySuper = _;
        <stable> <accessor> def TestHandler(): MySuper = TestingOutTraits.this.TestHandler;
          def main(args: Array[java.lang.String]): Unit = {
          val result: java.lang.String = TestingOutTraits.this.TestHandler().start();
          java.this.lang.System.out.println("result=".+(result))
          };
          def this(): object TestingOutTraits = {
          TestingOutTraits.super.this();
          TestingOutTraits.this.TestHandler = {
            new anonymous class TestingOutTraits$$anon$1()
          };
          ()
          }
          };
          abstract trait MySuper extends java.lang.Object with ScalaObject {
          def filter(): java.lang.String;
          def start(): java.lang.String
          };
          abstract trait MyTrait extends java.lang.Object with ScalaObject { self: MyTrait =>
            def createdFilter(): java.lang.String;
            override def filter(): java.lang.String
          };
          abstract trait MySuper$class extends  {
          def filter($this: MySuper): java.lang.String = "first part to->";
          def start($this: MySuper): java.lang.String = $this.filter();
          def /*MySuper$class*/$init$($this: MySuper): Unit = {
            ()
          }
          };
          abstract trait MyTrait$class extends  { self: MyTrait =>
            def createdFilter($this: MyTrait): java.lang.String = "override this";
            override def filter($this: MyTrait): java.lang.String = $this.$asInstanceOf[MySuper]().filter().+($this.createdFilter());
        def /*MyTrait$class*/$init$($this: MyTrait): Unit = {
          ()
        }
        };
        final class TestingOutTraits$$anon$1 extends java.lang.Object with MySuper with MyTrait {
        override def filter(): java.lang.String = MyTrait$class.filter(TestingOutTraits$$anon$1.this);
        def start(): java.lang.String = MySuper$class.start(TestingOutTraits$$anon$1.this);
        override def createdFilter(): java.lang.String = "second part";
        def this(): anonymous class TestingOutTraits$$anon$1 = {
          TestingOutTraits$$anon$1.super.this();
          MySuper$class./*MySuper$class*/$init$(TestingOutTraits$$anon$1.this);
          MyTrait$class./*MyTrait$class*/$init$(TestingOutTraits$$anon$1.this);
          ()
        }
        }