冲突的嵌套继承特征

时间:2010-01-15 16:47:44

标签: scala traits

假设我有以下代码:

trait Trait1 { 
  trait Inner {
    val name = "Inner1"
  }
}

trait Trait2 {
  trait Inner {
    val name = "Inner2"
  }
}

class Foo extends Trait1 with Trait2 {
  // I want Concrete1 to be a Trait1.Inner not a Trait2.Inner
  class Concrete1 extends Inner
  val c = new Concrete1
}

object Obj {
  def main(args: Array[String]): Unit = {
    val foo = new Foo
    println(foo.c.name)
  }
}

当我混入Trait1Trait2时,引用Inner似乎默认为Inner类型,其中我混合的第二个特征;所以当我调用Obj的{​​{1}}方法时,会打印main。如何在Inner2中引用Trait1.Inner?以下所有三个都会产生编译器错误:

Foo

4 个答案:

答案 0 :(得分:6)

而不是

class Concrete1 extends Inner

使用此

class Concrete1 extends super[Trait1].Inner

那应该能得到你想要的东西

答案 1 :(得分:4)

模板中有两个名称空间(模板是类,对象或特征的主体。)

  1. 成员:vals,vars,defs和嵌套对象
  2. 类型:类型别名,嵌套特征和嵌套类
  3. 从多个父模板继承时,这些名称空间中的冲突将通过类线性化来解决。

    您可以重新订购继承,将所需的父级内部版本添加到您的课程中,或者找到替代设计。

答案 2 :(得分:3)

一个选项(如果您可以侵入特征)是将每个内部特征定义为具有非冲突名称的类型成员。

trait Trait1 {
  type Inner1 = Inner
  trait Inner {
    val name = "Inner1"
  }
}

trait Trait2 {
  type Inner2 = Inner
  trait Inner {
    val name = "Inner2"
  }
}

class Foo extends Trait1 with Trait2 {
  class Concrete1 extends Inner1
  class Concrete2 extends Inner2
  val c1 = new Concrete1
  val c2 = new Concrete2
}

object App extends Application {
  val foo = new Foo
  println(foo.c1.name) // Inner1
  println(foo.c2.name) // Inner2
}

如果您不能侵入原始特征(Trait1和Trait2),您可以扩展它们以定义类型成员。

trait Trait1 {
  trait Inner {
    val name = "Inner1"
  }
}
trait Trait2 {
  trait Inner {
    val name = "Inner2"
  }
}

trait Trait1a extends Trait1 {
  type Inner1 = Inner
}
trait Trait2a extends Trait2 {
  type Inner2 = Inner
}

class Foo extends Trait1a with Trait2a {
  class Concrete1 extends Inner1
  class Concrete2 extends Inner2
  val c1 = new Concrete1
  val c2 = new Concrete2
}

另一种方法是使用中间特征来定义你的第一个具体类:

trait Trait1 {
  trait Inner {
    val name = "Inner1"
  }
}
trait Trait2 {
  trait Inner {
    val name = "Inner2"
  }
}

trait FooIntermediate extends Trait1 {
  class Concrete1 extends Inner
}

class Foo extends FooIntermediate with Trait2 {
  class Concrete2 extends Inner
  val c1 = new Concrete1
  val c2 = new Concrete2
}

答案 3 :(得分:2)

为什么不按照您希望它们具有优先顺序排列特征?特征的线性化不是任意的,而是指定的。