Ich bin nicht in der Lage zu verstehen , und ich konnte nicht die Bedeutung finde heraus Schlüsselwort in Kotlin.
Sie können das Beispiel hier überprüfen:
List<out T>
Wenn jemand die Bedeutung davon erklären kann. Es wäre sehr dankbar.
Ich bin nicht in der Lage zu verstehen , und ich konnte nicht die Bedeutung finde heraus Schlüsselwort in Kotlin.
Sie können das Beispiel hier überprüfen:
List<out T>
Wenn jemand die Bedeutung davon erklären kann. Es wäre sehr dankbar.
Antworten:
Mit dieser Unterschrift:
List<out T>
du kannst das:
val doubleList: List<Double> = listOf(1.0, 2.0)
val numberList: List<Number> = doubleList
was bedeutet , T ist kovarianten :
Wenn ein Typparameter T einer Klasse C deklariert wird , kann C <Basis> sicher ein Supertyp von C <Derived> sein .
Dies ist Kontrast mit in , zB
Comparable<in T>
du kannst das:
fun foo(numberComparable: Comparable<Number>) {
val doubleComparable: Comparable<Double> = numberComparable
// ...
}
was bedeutet , T ist kontra :
wenn ein Typparameter T einer Klasse C wird erklärt in , C <Derived> kann sicher sein , übergeordnete Typ von C <Base> .
Eine andere Art, sich daran zu erinnern:
Verbraucher in , Produzent aus .
siehe Kotlin Generics Varianz
----------------- aktualisiert am 4. Januar 2019 -----------------
Für " Consumer in, Producer out " lesen wir nur von der Producer-Call-Methode, um das Ergebnis vom Typ T zu erhalten. und schreiben Sie nur in die Consumer-Call-Methode, indem Sie den Parameter vom Typ T übergeben.
Im Beispiel für List<out T>
ist es offensichtlich, dass wir dies tun können:
val n1: Number = numberList[0]
val n2: Number = doubleList[0]
So ist es sicher zu liefern, List<Double>
wann List<Number>
erwartet wird, daher List<Number>
ist super Typ List<Double>
, aber nicht umgekehrt.
Im Beispiel für Comparable<in T>
:
val double: Double = 1.0
doubleComparable.compareTo(double)
numberComparable.compareTo(double)
So ist es sicher zu liefern, Comparable<Number>
wann Comparable<Double>
erwartet wird, daher Comparable<Double>
ist super Typ Comparable<Number>
, aber nicht umgekehrt.
out
Teil ist jedoch nicht das, was List
unveränderlich macht . Sie können ganz einfach eine eigene List<out T>
Schnittstelle erstellen, die über eine clear()
Methode verfügt , da keine Argumente erforderlich sind.
List<out T> is like List<? extends T> in Java
und
List<in T> is like List<? super T> in Java
Zum Beispiel können Sie in Kotlin Dinge wie tun
val value : List<Any> = listOf(1,2,3)
//since List signature is List<out T> in Kotlin
List<out T>
bedeutet, dass Sie tun können, val list: List<Number> = listOf<Int>()
weil Int
es sich um einen abgeleiteten Typ von handelt Number
. Das entsprechende Java wäreList<? extends Number> list = new ArrayList<Integer>();
Siehe das Handbuch von Kotlin
Der Kotlin-
List<out T>
Typ ist eine Schnittstelle, die schreibgeschützte Operationen wie size, get usw. bereitstellt. Wie in Java erbt es vonCollection<T>
und das wiederum erbt vonIterable<T>
. Methoden, die die Liste ändern, werden von derMutableList<T>
Schnittstelle hinzugefügt . Dieses Muster gilt auch fürSet<out T>/MutableSet<T>
undMap<K, out
V>/MutableMap<K, V>
Und das,
In Kotlin gibt es eine Möglichkeit, dem Compiler so etwas zu erklären. Dies wird als Varianz der Deklarationssite bezeichnet: Wir können den Typparameter T von Source mit Anmerkungen versehen, um sicherzustellen, dass er nur von Mitgliedern von zurückgegeben (produziert)
Source<T>
und niemals verbraucht wird. Dazu stellen wir den Modifikator out zur Verfügung:
> abstract class Source<out T> { > abstract fun nextT(): T } > > fun demo(strs: Source<String>) { > val objects: Source<Any> = strs // This is OK, since T is an out-parameter > // ... }
Die allgemeine Regel lautet: Wenn ein Typparameter
T
einer KlasseC
als deklariert wird, kann er nur in der Out-Position in den Mitgliedern von auftretenC
, kann aber im GegenzugC<Base>
sicher ein Supertyp von seinC<Derived>
.In "klugen Worten" sagen sie, dass die Klasse
C
im Parameter kovariantT
ist oder dassT
es sich um einen kovarianten Typparameter handelt. Sie können sich C als Produzenten von T's und NICHT als Konsument vonT
's vorstellen. Der Out-Modifikator wird als Varianzanmerkung bezeichnet. Da er an der Deklarationsstelle für Typparameter bereitgestellt wird, wird von der Varianz der Deklarationsstelle gesprochen. Dies steht im Gegensatz zu Javas Varianz der Verwendungsorte, bei der Platzhalter in den Typverwendungen die Typen kovariant machen.
List<out T>
Erklärung ist,out
dass sie unveränderlich ist (im Vergleich zu veränderlichen Sammlungen, die keine haben). Es kann hilfreich sein, dies in der Antwort zu erwähnen und hervorzuheben. Implizites Casting ist eher eine Folge dieses als eines Hauptpunkts (da man nicht in Liste <Nummer> schreiben kann, kann man es sicher als Referenz auf Liste <Doppel> haben).