Was macht [B >: A] tun, in Scala?
Was bedeutet [B >: A]
bedeutet in Scala? Und was sind die Auswirkungen?
Beispiel Referenz: http://www.scala-lang.org/node/129
class Stack[+A] {
def push[B >: A](elem: B): Stack[B] = new Stack[B] {
override def top: B = elem
override def pop: Stack[B] = Stack.this
override def toString() = elem.toString() + " " + Stack.this.toString()
}
def top: A = error("no element on stack")
def pop: Stack[A] = error("no element on stack")
override def toString() = ""
}
object VariancesTest extends Application {
var s: Stack[Any] = new Stack().push("hello");
s = s.push(new Object())
s = s.push(7)
println(s)
}
- Die Beurteilung durch den Zusammenhang, es sieht aus wie "erlauben B repräsentieren eine Klasse, das ist auch darstellbar durch Ein" aber das ist nur eine Vermutung.
- Versuchen Sie, diese auf der REPL:
val s1 = new Stack().push("hello"); val s2 = s1.push(new Object()); val s3 = s2.push(7)
- wie s1, s2 und s3 unterscheiden? (Dieser verbirgt sich hinter derStack[Any]
Art gegeben s; daran erinnern, dass Alle ist der oberste Typ in der Scala, dem nicht widersprechen.) - Duplikat von stackoverflow.com/questions/4869988/...
- Schade, der ganz und gar nicht kommen, wenn ich suchte für ähnliche Fragen vor der Buchung. Ich Stimme zu halten, diese tollen Antworten..
- Kennzeichnung als Duplikat löschen nicht Antworten, doch der Aufbau einer web-Duplikaten tatsächlich hilft sehen große Bild von dem problem (und ALLE Antworten). Ich bin nicht überrascht, Sie nicht schlagen, die post, das Thema ist völlig anders :-).
Du musst angemeldet sein, um einen Kommentar abzugeben.
[B >: A]
ist eine niedrigere Typ-gebunden. Es bedeutet, dassB
gebunden ist ein obertyp vonA
.Ähnlich
[B <: A]
ist eine Obere Typ gebunden, was bedeutet, dassB
beschränkt sich auf ein Untertyp vonA
.In dem Beispiel, das Sie gezeigt haben, dürfen Sie push ein element vom Typ
B
auf einem Stapel mitA
Elemente, aber das Ergebnis ist ein Stapel vonB
Elemente.Der Seite, wo Sie sah, das eigentlich einen link zu einer anderen Seite über untere Typ-Schranken, die ein Beispiel zeigt die Wirkung.
X <: Y
bedeutet, dass Typ-parameterX
muss ein Subtyp des TypsY
.X >: Y
bedeutet das Gegenteil,X
muss ein super Typ derY
(in beiden FällenX = Y
ist ok). Diese notation kann gegen die intuition, dass man meinen könnte, ein Hund ist mehr als ein Tier (konkret in der Programmierung Bedingungen, mehr Dienstleistungen), aber genau aus dem Grund ist es genauer, gibt es weniger Hunde als Tiere, die ArtAnimal
enthält mehr Werte, als der TypDog
es enthält alle Hunde, und alle Strauße zu. SoAnimal
>:Dog
.Als für der Grund, warum
push
hat diese Signatur, ich bin nicht sicher, ich kann es besser erklären, als die Seite das Beispiel stammt aus, aber lassen Sie mich versuchen.Es beginnt mit der Varianz. Die
+
imclass Stack[+A]
bedeutet, dassStack
istcovariant in A
. wennX
ist ein Subtyp desY
,Stack[X]
wird ein Untertyp vonStack[Y]
. Ein Stapel von Hunden ist auch ein Stapel Tiere. Für die mathematisch, wenn man sieht-Stapel als eine Funktion vom Typ (X ist eine Art, wenn Sie es passieren zu Stapeln, die Sie bekommen, Stack[X], das ist eine andere Art) als kovariante bedeutet, dass es ist eine steigende Funktion (mit <: die subtypisierung Zusammenhang wird die orders-on-Typen).Scheint dies Recht, aber das ist nicht so eine einfache Frage. Wäre es nicht so, mit einem push-routine, ändert es, hinzufügen eines neuen Elements, das ist
(das Beispiel ist anders, schieben gibt einen neuen Stapel, verlassen
this
unverändert). Natürlich, ein Stack[Hund] sollte nur akzeptieren Hunden getrieben zu werden, es. Andernfalls wäre es nicht mehr einen Stapel von Hunden. Aber wenn wir es akzeptieren behandelt werden als ein Stapel von Tieren, die wir tun könnten,Klar, ist die Behandlung dieses stack als kovariante ist ungesund. Wenn der gesamte Stapel wird als ein
Stack[Animal]
eine operation zulässig ist, sonst wäre es nicht aufStack[Dog]
. Was wurde hier gemacht mit dem push-getan werden kann mit eine beliebige routine, nimmt als argument. Wenn eine generische Klasse ist gekennzeichnet als kovariante, mit C[+A], dann ist A nicht der Typ der jedes argument von jedem (öffentlich) - routine des C, und der compiler erzwingen.Aber der stack im Beispiel ist das anders. Hätten wir eine
def push(a: A): Stack[A]
. Wenn man ruftpush
bekommt man einen neuen Stapel, und den original-stack bleibt unverändert, es ist immer noch eine richtige Stack[Hund], was auch immer geschoben. Wenn wir das tundogs
ist immer noch die gleiche und noch eineStack[Dog]
. OffensichtlichnewStack
ist nicht. Noch ist es einStack[Ostrich]
, weil es enthält auch die Hunde, die waren (und sind) in der ursprünglichen Stapel. Aber es wäre eine richtigeStack[Animal]
. Drückt man eine Katze, genauer wäre es zu sagen, es ist einStack[Mammal]
(während Sie einen Stapel Tiere auch). Drückt man12
, es wird nur einStack[Any]
, der einzige gemeinsame obertyp vonDog
undInteger
. Das problem ist, dass der compiler hat keine Möglichkeit zu wissen, dass dieser Anruf ist sicher, und wird nicht zulassen, dass diea: A
argument indef push(a: A): Stack[A]
wennStack
gekennzeichnet ist covariant. Wenn es dort angehalten, eine kovariante stack wäre nutzlos, da es keine Möglichkeit gäbe, zu setzen Werte.Die Signatur löst das problem:
Wenn
B
ist ein Vorfahre vonA
beim hinzufügen einesB
bekommt man einStack[B]
. Daher ist das hinzufügen einesMammal
zu einemStack[Dog]
gibt eineStack[Mammal]
Sie ein Tier gibt einemStack[Animal]
, was in Ordnung ist. Hinzufügen ein Hund ist auch ok, A >: A ist wahr.Ist das gut, aber scheint zu restriktiv. Was ist, wenn das hinzugefügte Element Typ ist kein Vorfahr von
A
? Was zum Beispiel, wenn es ein Nachfahre e.gdogs.push(goldenRetriever)
. Man kann nicht nehmenB = GoldenRetriever
hat man nichtGoldenRetriever >: Dog
sondern das Gegenteil. Doch, kann man nehmen, B = Hund, alles in Ordnung. Es werden die parameter elem wird erwartet, dass der Typ Hund, wir passieren kann natürlich passieren ein GoldenRetriever. Man bekommt einen Stapel von B, noch einen Stapel von Hunden. Und es ist richtig, dassB = GoldenRetriever
war nicht erlaubt. Das Ergebnis hätte typisiert alsStack[GoldenRetriever]
, das wäre falsch, weil der Stapel enthielt irish setter zu.Was ostrishes? Gut
Ostrich
ist weder ein Supertyp, noch ein Untertyp vonDog
. Aber genauso, wie man hinzufügen kann, ein goldenRetriever, weil es ist ein Hund, und es ist möglich, ein Hund, ein Strauß ist ein Tier, und es ist möglich, ein Tier. Also wobei B = Tier - >: Hund arbeitet, und so ein, wenn man einen Strauß bekommt man einStack[Animal]
.Machen den stack kovariante Kraft, diese Signatur, die komplexer sind als die naiven
push(a: A) : Stack[A]
. Aber wir gewinnen eine routine, die ist völlig flexibel, kann alles Hinzugefügt werden, nicht nur einA
, und doch, die Typen das Ergebnis so genau wie möglich sein. Und die tatsächliche Implementierung außer für die Typen-Deklarationen, ist die gleiche, es hätte mitpush(a: A)
.Stack is covariant in A
. Können Sie bitte erklärenAls einen großen überblick finden Sie in der git-Seite von @retronym