Scala特征和结构类型:特征是否可以扩展结构类型然后调用super?

时间:2012-03-02 18:48:26

标签: scala

我希望有一个特点,可以a)用特定的方法混合到任何类中,并且b)可以调用super。像这样:

  // A and B are from a library that I don't control.  No changes allowed here.
  class A {
    def stuff = "a stuff"
  }
  class B {
    def stuff = "b stuff"
  }

  // My code starts here

  type HasStuffMethod = {
    def stuff: String
  }

  // Note that this doesn't compile - gets:
  //   class type required but AnyRef{def stuff: String} found
  trait ImplementsStuff extends HasStuffMethod {
    override def stuff = "trait + " + super.stuff
  }

  val a = new A with ImplementsStuff
  assert(a.stuff == "trait + a stuff")

  val b = new B with ImplementsStuff
  assert(b.stuff == "trait + b stuff")

有没有办法做到这一点?

请注意,我不控制A和B;他们来自另一个我无法修改的图书馆。

[编辑 - 看到答案后添加]

有没有办法以这样的方式调用原始方法?

  trait ImplementsStuff {
    this: HasStuffMethod =>
    abstract override def stuff = "foo" + "how do I call the original method here?"
  }

这没用,因为当你把它混合成它给出的东西时:

  

错误:在类A =>的A类中覆盖方法内容java.lang.String中;   特征中的方法东西类型=>的ImplementsStuff java.lang.String中   如果没有第三个成员,则不能覆盖具体成员   被两者所覆盖(这条规则旨在防止“意外”   覆盖 '')

但这不是偶然的;是的,我真的希望你完全采用现有的方法。然后让我也称之为。

3 个答案:

答案 0 :(得分:5)

我可以想到两个选择:

选项1,使用自我类型注释并从新方法(我想象地称为stuff)调用callStuff而不是覆盖它。

  trait ImplementsStuff  {
    this: HasStuffMethod =>
    def callStuff = "trait + " + this.stuff
  }

  val a = new A with ImplementsStuff
  assert(a.callStuff == "trait + a stuff")

  val b = new B with ImplementsStuff
  assert(b.callStuff == "trait + b stuff")

选项2(因为你说你不控制A和B)是亲爱的旧装饰模式。

  trait HasStuff { def stuff: String }

  class DecorateStuff(decorated: HasStuffMethod) extends HasStuff {
    def stuff = "trait + " + decorated.stuff
  }
  val decA = new DecorateStuff(new A)
  assert(decA.stuff == "trait + a stuff")

  val decB = new DecorateStuff(new B)
  assert(decB.stuff == "trait + b stuff")

答案 1 :(得分:4)

在这种情况下你需要abstract override

答案 2 :(得分:1)

没有办法在Scala中扩展精炼类型(我不确定这可以安全地拉出来,但探索它会很有趣)。

我有一个更详细的解决方案,但让你更接近你的目标。

trait HasStuff {
  def theirStuff: String
}

trait ImplementsStuff extends HasStuff {
  def stuff = "trait + " + theirStuff
}

请注意,我没有精炼类型,而是具有特征,并在实现中扩展它。我需要手动添加超级访问者,我通过委托来做。 HasStuff定义了它们,我在mixin网站上实现它们:

val a = new A with ImplementsStuff {
  def theirStuff = super[A].stuff

  override def stuff = super[ImplementsStuff].stuff
}

val b = new B with ImplementsStuff {
  def theirStuff = super[B].stuff

  override def stuff = super[ImplementsStuff].stuff
}

在mixin站点,我需要实现超级访问器(theirStuff)以转发到正确的继承方法。我还需要在此级别覆盖stuff,因为ImplementsStuff不会继承stuff方法,因此它不能override

stuffa上拨打b表示已被覆盖:

$ a.stuff
res0: java.lang.String = trait + a stuff

$ b.stuff
res1: java.lang.String = trait + b stuff