2010-01-15 36 views
7

假设我有以下代码:冲突的嵌套遗传性状

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类型为准特质我混入第二的;所以当我拨打Objmain方法时,它会打印Inner2。我如何参考Foo中的Trait1.Inner?所有这三个下面给编译器错误的:

class Concrete1 extends Trait1.Inner 
class Concrete1 extends Trait1$Inner 
class Concrete1 extends Trait1#Inner 

回答

6

而不是

class Concrete1 extends Inner 

使用此

class Concrete1 extends super[Trait1].Inner 

应得到你什么哟你想

+0

这很棒,我现在可以编写类Concrete1扩展超[Trait1]。内部和类Concrete2扩展超[Trait2] .Inner并具有两种类型的Inner in Foo的实例。 – ams 2010-01-16 11:07:44

2

为什么不下令在你期望他们有优先顺序的特质?性状的线性化不是任意的,而是指定的。

+0

是的,我想过这样做。但是,假设我想创建一个Concrete2 extends Trait2.Inner。然后怎样呢? – ams 2010-01-15 17:55:18

4

有一个模板内的两个命名空间(模板是一个类,对象,或性状的主体。)

  1. 成员:瓦尔斯,乏,并DEFS和嵌套对象
  2. 类型:类型别名,嵌套特性和嵌套类

当从多个父模板继承时,这些名称空间中的冲突通过类线性化来解决。

您可以对您的继承进行重新排序,以将所需的父Inner带入您的类中,或者找到替代设计。

+0

谢谢,我没有想到成员特征会被覆盖。当你考虑它时有意义! – ams 2010-01-15 18:26:39

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 
} 
+0

谢谢,我曾想过要做类型Inner1 = Inner。尽管如此,我还没有想过你的其他两种选择。现在我有太多的选择:) – ams 2010-01-15 18:28:05