Es wird vor allem verwendet für Injektion von Abhängigkeiten wie z. B. beim Tortenmuster. Es gibt eine großartiger Artikel über viele verschiedene Formen von Dependency Injection in Scala, einschließlich des Cake Patterns. Wenn Sie "Cake Pattern und Scala" googeln, erhalten Sie viele Links, einschließlich Präsentationen und Videos. Für den Moment ist hier ein Link zu weitere Frage .
Was nun der Unterschied zwischen einem Selbsttyp und der Erweiterung einer Eigenschaft ist, ist ganz einfach. Wenn Sie sagen B extends A
dann B
es eine A
. Wenn Sie Selbsttypen verwenden, B
erfordert eine A
. Es gibt zwei spezifische Anforderungen, die mit Selbsttypen geschaffen werden:
- Si
B
erweitert wird, dann sind Sie erforderlich zum Einmischen eines A
.
- Wenn eine konkrete Klasse schließlich diese Traits erweitert/vermischt, muss eine Klasse/ein Trait Folgendes implementieren
A
.
Betrachten Sie die folgenden Beispiele:
scala> trait User { def name: String }
defined trait User
scala> trait Tweeter {
| user: User =>
| def tweet(msg: String) = println(s"$name: $msg")
| }
defined trait Tweeter
scala> trait Wrong extends Tweeter {
| def noCanDo = name
| }
<console>:9: error: illegal inheritance;
self-type Wrong does not conform to Tweeter's selftype Tweeter with User
trait Wrong extends Tweeter {
^
<console>:10: error: not found: value name
def noCanDo = name
^
Si Tweeter
war eine Unterklasse von User
würde es keinen Fehler geben. In dem obigen Code müssen wir erforderlich a User
wenn Tweeter
verwendet wird, jedoch eine User
nicht zur Verfügung gestellt wurde Wrong
und wir bekamen einen Fehler. Nun, mit dem Code oben immer noch in Reichweite, betrachten:
scala> trait DummyUser extends User {
| override def name: String = "foo"
| }
defined trait DummyUser
scala> trait Right extends Tweeter with User {
| val canDo = name
| }
defined trait Right
scala> trait RightAgain extends Tweeter with DummyUser {
| val canDo = name
| }
defined trait RightAgain
Mit Right
das Erfordernis der Einmischung eines User
erfüllt ist. Die zweite oben genannte Voraussetzung ist jedoch nicht erfüllt: Die Last der Umsetzung User
bleibt für Klassen/Traits, die die Right
.
Mit RightAgain
beide Anforderungen erfüllt sind. A User
und eine Implementierung von User
sind vorgesehen.
Weitere praktische Anwendungsfälle finden Sie unter den Links am Anfang dieser Antwort! Aber jetzt haben Sie es hoffentlich verstanden.
0 Stimmen
Ich interessiere mich eigentlich für die Unterschiede zwischen Selbsttypen und Unterklassen in Traits. Ich kenne einige der üblichen Verwendungszwecke für Selbsttypen; ich kann nur keinen Grund finden, warum sie nicht auf die gleiche Weise mit Subtypisierung durchgeführt werden sollten.
35 Stimmen
Man kann Typparameter innerhalb von Selbsttypen verwenden:
trait A[Self] {this: Self => }
ist legal,trait A[Self] extends Self
ist es nicht.4 Stimmen
Ein Selbsttyp kann auch eine Klasse sein, aber ein Trait kann nicht von einer Klasse erben.
10 Stimmen
@cvogt: ein Trait kann von einer Klasse erben (zumindest ab 2.10): pastebin.com/zShvr8LX
1 Stimmen
@Blaisorblade: Ist das nicht etwas, das durch eine kleine Umgestaltung der Sprache gelöst werden könnte, und keine grundlegende Einschränkung? (zumindest vom Standpunkt der Frage aus gesehen)
0 Stimmen
@ErikAllik: Ich habe von dieser Einschränkung aus dem Papier erfahren, in dem das Kuchenmuster "skalierbare Komponentenabstraktionen" beschrieben wird, daher bezweifle ich, dass das ein Zufall ist. Ich vermute, dass die Gründe einfach auf die Einschränkungen der JVM zurückzuführen sind und nicht auf tiefere Beweggründe, aber das bedeutet nicht unbedingt, dass eine Lösung möglich ist.
0 Stimmen
Ich fand diesen Selbsttyp sehr nützlich, um Klassen, die einen Trait implementieren, mitzuteilen, dass sie einen (versiegelten) trait-Enum . Siehe dies: stackoverflow.com/q/36066238/1206998