Warum ist der Parametertyp cons
falsch?
trait List[+A] {
def cons(hd: A): List[A]
}
Compiler geben Sie Fehler:
covariant type A occurs in contravariant position in type A of value hd
weil Methodenparameter als kontra Positionen zählen, aber A
covariant ist.
Stellen wir uns vor, dass diese Methodendeklaration kompilieren würde. Dann könnten wir tun:
class ListImpl[A] extends List[A] {
override def cons(hd: A): List[A] = ???
}
val strings: List[String] = new ListImpl[String]
val values: List[Any] = strings // OK, since List[String] <: List[Any] (in List[A], A is covariant)
values.cons(13) // OK(??), since values's static type is List[Any], so argument of cons should be Any, and 13 conforms to type Any
Ist die letzte Zeile oben wirklich OK? Wir rufen cons
auf values
. values
ist das gleiche wie strings
, und strings
ist Objekt des Typs ListImpl[String]
. So cons
Aufruf in der letzten Zeile erwartet String
Argument, aber wir übergeben Int
, weil values
ist statischer Typ List[Any]
und Int
entspricht Any
. Irgendetwas stimmt hier definitiv nicht - welche Linie ist schuld? Die Antwort lautet: cons
Methodendeklaration. Um dieses Problem zu beheben, müssen wir den kovarianten Typ-Parameter A
aus der kontravarianten Position entfernen (in cons
Deklaration). Alternativ können wir A
nicht-kovariant machen.
Siehe auch diese Fragen: #1, #2.
... nicht cons
lief in Problem?
trait List[+A] {
def cons[B >: A](v: B): List[B]
}
val animal_list: List[Animal] = List(tiger, dog) // We are assuming that List.apply and concrete implementation of List is somewhere defined.
Nein, animal_list.cons(tiger)
Aufruf typ korrekt.
Ich gehe davon aus, dass Animal
ist üblich, übergeordneter Typ von Dog
und Tiger
, und dass dog
und tiger
sind Instanzen von Dog
und Tiger
sind.
In animal_list.cons(tiger)
Aufruf beider A
und B
Typparameter sind Animal
instanziiert, so cons
Methode nimmt Form von:
def cons[Animal >: Animal](v: Animal): List[Animal]
Animal >: Animal
Einschränkung erfüllt ist, weil:
Supertype and subtype relationships are reflexive, which means a type is both a supertype and a subtype of itself. [ source ]
Das Argument cons
ist Tiger
, was dem Typ Animal
entspricht, also ist der Methodenaufruf Typ-c orrect.
Beachten Sie, dass, wenn Sie B
zwingen Tiger
instanziiert werden, wie animal_list.cons[Tiger](tiger)
, dann wird dieser Aufruf nicht typ richtig, und Sie werden Compiler-Fehler.
Siehe ähnliches Beispiel .
Oh ich sehe, also der Grund, dass "Tiger" trotz "Tiger <: Animal" zu "cons" übergehen konnte, ist, weil 'Tiger' zuerst in' Animal' getypt wird? – testing
@testing - Mit der Deklaration 'def cons [B>: A] (v: B): Liste [B]' können Sie ein beliebiges Objekt an 'cons' übergeben - das Typargument' B' wird immer am häufigsten instanziiert genauer gemeinsamer Typ von "A" und die Art von "cons" -Argument. Das Übergeben des Objekts an die Methode, die das Argument supertype erwartet, ist ein normales OO-Ding - e. G. Sie können Tiger jederzeit passieren, wenn "Animal" erwartet wird. – TeWu
Was ist, wenn ich 'val tiger_list: List [Tiger] = List (tiger)' habe, würde dies bedeuten, dass "tiger_list.con (animal)" gültig ist? sollten wir nicht so etwas haben wie 'def cons [B>: A] [C <: A] (v: B): Liste [C]' – testing