Frage

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 einmischen Trait1 und Trait2, in Bezug auf Inner scheint standardmäßig an der Inner Art der Merkmale, die ich zweiter habe; Also, wenn ich anrufe Obj's main Methode es druckt Inner2. Wie kann ich mich beziehen Trait1.Inner in Foo? Alle drei folgenden Fehlern geben Compiler -Fehler:

class Concrete1 extends Trait1.Inner
class Concrete1 extends Trait1$Inner
class Concrete1 extends Trait1#Inner
War es hilfreich?

Lösung

Anstatt von

class Concrete1 extends Inner

Benutze das

class Concrete1 extends super[Trait1].Inner

Das sollte dir das bringen, was du willst

Andere Tipps

In einer Vorlage gibt es zwei Namespaces (Vorlage ist der Körper einer Klasse, eines Objekts oder eines Merkmals).

  1. Mitglieder: VALS, VARS und DEFS und verschachtelte Objekte
  2. Typen: Typ Aliase, verschachtelte Merkmale und verschachtelte Klassen

Wenn Sie von mehreren übergeordneten Vorlagen erben, werden Konflikte in diesen Namespaces durch die Klassenlinearisierung gelöst.

Sie können Ihr Erbe neu ordnen, um das gewünschte Elternteil innerlich in Ihre Klasse zu bringen oder ein alternatives Design zu finden.

Eine Option (wenn Sie in den Merkmalen invasiv sein können) besteht darin, jedes innere Merkmal als Typelement zu definieren, das einen nicht konfliktierenden 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 den ursprünglichen Merkmalen (Merkmal1 und Merkmal2) nicht invasiv sein können, können Sie sie erweitern, um das Typ -Mitglied 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 die Verwendung eines mittleren Merkmals, 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
}

Warum nicht die Eigenschaften in der Reihenfolge bestellen, von der Sie erwarten, dass sie Vorrang haben? Die Linearisierung von Merkmalen ist nicht willkürlich, sondern angegeben.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top