Widersprüchliche verschachtelte erbte Merkmale
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
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).
- Mitglieder: VALS, VARS und DEFS und verschachtelte Objekte
- 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.