代码之家  ›  专栏  ›  技术社区  ›  ams

嵌套继承特征冲突

  •  7
  • ams  · 技术社区  · 15 年前

    假设我有以下代码:

    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)
      }
    }
    

    当我融入 Trait1 Trait2 ,指 Inner 似乎默认为 内部 我第二次混合的特征类型;所以当我打电话时 Obj main 打印方法 Inner2 . 我该怎么说呢 Trait1.Inner 在里面 Foo ?以下三项都会导致编译器错误:

    class Concrete1 extends Trait1.Inner
    class Concrete1 extends Trait1$Inner
    class Concrete1 extends Trait1#Inner
    
    4 回复  |  直到 15 年前
        1
  •  6
  •   Mushtaq Ahmed    15 年前

    而不是

    class Concrete1 extends Inner
    

    用这个

    class Concrete1 extends super[Trait1].Inner
    

    你想要什么就要什么

        2
  •  4
  •   retronym    15 年前

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

    1. 成员:VAL、var、def和嵌套对象
    2. 类型:类型别名、嵌套特性和嵌套类

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

    您可以重新排序继承以将所需的父类内部引入类中,或者找到其他设计。

        3
  •  3
  •   Mitch Blevins    15 年前

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

    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
    }
    
        4
  •  2
  •   Daniel C. Sobral    15 年前

    为什么不按你期望的顺序排列这些特性呢?性状的线性化不是任意的,而是特定的。