冲突的嵌套遗传特征

发布于 2024-08-17 19:55:33 字数 839 浏览 8 评论 0原文

假设我有以下代码:

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 code> 我第二个混合的特征的类型;因此,当我调用 Objmain 方法时,它会打印 Inner2。如何在 Foo 中引用 Trait1.Inner?以下所有三个都会给出编译器错误:

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

Suppose I have the following code:

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

When I mix in Trait1 and Trait2, referring to Inner seems to default to the Inner type of whichever trait I mixin second; so when I call Obj's main method it prints Inner2. How can I refer to Trait1.Inner in Foo? All three of the following give compiler errors:

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

雨后咖啡店 2024-08-24 19:55:33

而不是

class Concrete1 extends Inner

使用这个,

class Concrete1 extends super[Trait1].Inner

这应该能让你得到你想要的

Instead of

class Concrete1 extends Inner

Use this

class Concrete1 extends super[Trait1].Inner

That should get you what you want

赠佳期 2024-08-24 19:55:33

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

  1. 成员:vals、vars 和 defs 以及嵌套对象
  2. 类型:类型别名、嵌套特征和嵌套类

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

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

There are two namespaces within a template (template being the body of a class, object, or trait.)

  1. Members: vals, vars, and defs and nested objects
  2. Types: types aliases, nested traits and nested classes

When inheriting from multiple parent templates, conflicts in these namespaces are resolved through class linearization.

You could re-order your inheritance to bring the desired parent Inner into your class, or find an alternative design.

遮云壑 2024-08-24 19:55:33

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

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
}

One option (if you can be invasive to the traits) is to define each Inner trait as a type member that has a non-conflicting name.

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
}

If you cannot be invasive to the original traits (Trait1 and Trait2), you can extend them to define the type member.

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
}

Another approach would be to use an intermediate trait to define your first concrete class:

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
}
笑,眼淚并存 2024-08-24 19:55:33

为什么不按照您期望的优先顺序对特征进行排序呢?特征的线性化不是任意的,而是指定的。

Why not order the traits in the order you expect them to have precedence? The linearization of traits is not arbitrary, but specified.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文