是否可以从自我类型调用重写方法?

时间:2016-04-29 18:36:50

标签: scala

考虑一下:

 class Foo { def foo = "foo" }
 trait Bar { self: Foo =>
    override def foo = "bar"
 }

我惊喜地发现这是可能的,并按预期工作:

new Foo with Bar foo 

返回" bar"。问题是Bar.foo是否有可能调用Foo.foo,就像人们经常在"普通"}中那样。继承案。 override def foo = super.foo + "bar"不起作用(说" foo不是AnyRef的成员),override def foo = self.foo + "bar"也没有(它最终只调用自身,导致无限递归)。 我尝试了一些其他组合(例如self.Foo.fooFoo.this.foo等),但没有任何运气。

这是不可能的吗?

3 个答案:

答案 0 :(得分:3)

没有。从自我类型调用重写方法是不可能的。

首先,特质Bar不是课程Foo的继承者,因此无法使用super.foo

其次,使用self.foo也是不可能的,因为self实际上是Bar with Foo类型。可以通过在typer

之后打印程序来显示它
$ scalac -Xprint:typer test.scala
[[syntax trees at end of                     typer]] // test.scala
package <empty> {
  class Foo extends scala.AnyRef {
    def <init>(): Foo = {
      Foo.super.<init>();
      ()
    };
    def foo: String = "foo"
  };
  abstract trait Bar extends scala.AnyRef { self: Bar with Foo => 
    def /*Bar*/$init$(): Unit = {
      ()
    };
    override def foo: String = "bar"
  };
  class FooBar extends Foo with Bar {
    def <init>(): FooBar = {
      FooBar.super.<init>();
      ()
    }
  };
  object TestApp extends scala.AnyRef {
    def <init>(): TestApp.type = {
      TestApp.super.<init>();
      ()
    };
    def main(args: Array[String]): Unit = {
      val a: FooBar = new FooBar();
      scala.this.Predef.println(a.foo)
    }
  }
}

因此,self.foo您尝试访问特征foo的方法Bar。此类行为与Scala Specification(PDF)匹配:

  

模板语句的序列可以以形式为前缀   参数定义和箭头,例如x =&gt;或x:T =&gt;。如果是正式的   给出参数,它可以作为参考的别名   整个模板的主体。如果形式参数来了   对于类型T,此定义会影响自我类型S.   底层类或对象如下:设C为类的类型   或定义模板的特征或对象。如果给出了类型T   形式自我参数,S是T和C的最大下界。如果不是   给出类型T,S只是C.在模板内部,它的类型是   假设是S.

可以使用反射访问该方法,但我认为它不是您正在寻找的。

答案 1 :(得分:0)

我不知道任何特定的语法来解开基类和混合特征。 但是,通过区分重写方法和基类中的默认实现,可以轻松地手动实现结果:

class Foo { def foo = defaultFoo; def defaultFoo = "foo" }
trait Bar { self: Foo => override def foo = self.defaultFoo + "bar" }

正如预期的那样

new Foo with Bar foo == "foobar"
new Foo foo == "foo"

答案 2 :(得分:0)

你使你的特质扩展Foo而不是使用自我类型:

class Foo {def foo = "foo"}
trait Bar extends Foo {
  override def foo = super.foo + "bar"
}
new Foo with Bar foo // barfoo

另见this answer