7 Stimmen

Widersprüchliche verschachtelte vererbte Merkmale

Angenommen, ich habe den folgenden 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)
  }
}

Wenn ich untermische Trait1 y Trait2 Bezug nehmend auf Inner scheint standardmäßig auf die Inner Typ der jeweiligen Eigenschaft, die ich als zweites mixin aufrufe; wenn ich also Obj 's main Methode druckt es Inner2 . Wie kann ich mich auf Trait1.Inner en Foo ? Alle drei der folgenden Beispiele führen zu Compilerfehlern:

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

6voto

Mushtaq Ahmed Punkte 6282

Anstelle von

class Concrete1 extends Inner

Verwenden Sie diese

class Concrete1 extends super[Trait1].Inner

Damit sollten Sie bekommen, was Sie wollen

4voto

retronym Punkte 54220

Es gibt zwei Namensräume innerhalb einer Vorlage (Vorlage ist der Körper einer Klasse, eines Objekts oder eines Traits).

  1. Mitglieder: vals, vars und defs und verschachtelte Objekte
  2. Typen: Typen-Aliase, verschachtelte Traits und verschachtelte Klassen

Bei der Vererbung von mehreren übergeordneten Vorlagen werden Konflikte in diesen Namespaces durch Klassenlinearisierung aufgelöst.

Sie könnten Ihre Vererbung neu ordnen, um das gewünschte übergeordnete Innere in Ihre Klasse zu bringen, oder einen alternativen Entwurf finden.

3voto

Mitch Blevins Punkte 13056

Eine Möglichkeit (wenn Sie invasiv zu den Eigenschaften sein können) besteht darin, jede innere Eigenschaft als Typmitglied zu definieren, das einen nicht widersprüchlichen Namen hat.

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
}

Wenn Sie nicht in die ursprünglichen Eigenschaften (Trait1 und Trait2) eingreifen können, können Sie sie erweitern, um den Typ Member zu definieren.

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
}

Ein anderer Ansatz wäre, eine Zwischeneigenschaft zu verwenden, um Ihre erste konkrete Klasse zu definieren:

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
}

2voto

Daniel C. Sobral Punkte 290004

Warum ordnen Sie die Merkmale nicht in der Reihenfolge, in der Sie sie für vorrangig halten? Die Linearisierung von Merkmalen ist nicht willkürlich, sondern vorgegeben.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X