¿Qué es la palabra clave en kotlin?

85

No soy capaz de entender y no pude encontrar el significado de salir palabra clave en Kotlin.

Puede consultar el ejemplo aquí:

List<out T>

Si alguien puede explicar el significado de esto. Esto sera realmente apreciado.

Akshay Sood
fuente

Respuestas:

58

Con esta firma:

List<out T>

Puedes hacerlo:

val doubleList: List<Double> = listOf(1.0, 2.0)
val numberList: List<Number> = doubleList

lo que significa que T es covariante :

cuando un tipo de parámetro T de una clase C se declara a cabo , C <Base> puede ser de forma segura un supertipo de C <Derivado> .

Esto es contraste con en , por ejemplo,

Comparable<in T>

Puedes hacerlo:

fun foo(numberComparable: Comparable<Number>) {
  val doubleComparable: Comparable<Double> = numberComparable
  // ...
}

lo que significa que T es contravariante :

cuando un tipo de parámetro T de una clase C se declara en , C <Derivado> puede ser de forma segura un supertipo de C <Base> .

Otra forma de recordarlo:

Consumidor dentro , productor fuera .

ver Varianza genérica de Kotlin

----------------- actualizado el 4 de enero de 2019 -----------------

Para el " Consumidor dentro, Productor fuera ", solo leemos del método Producer - call para obtener el resultado de tipo T; y solo escribir al método de llamada al consumidor pasando el parámetro de tipo T.

En el ejemplo de List<out T>, es obvio que podemos hacer esto:

val n1: Number = numberList[0]
val n2: Number = doubleList[0]

Por lo tanto, es seguro proporcionarlo List<Double>cuando List<Number>se espera, por List<Number>lo tanto, es un súper tipo de List<Double>, pero no al revés.

En el ejemplo de Comparable<in T>:

val double: Double = 1.0
doubleComparable.compareTo(double)
numberComparable.compareTo(double)

Por lo tanto, es seguro proporcionarlo Comparable<Number>cuando Comparable<Double>se espera, por Comparable<Double>lo tanto, es un súper tipo de Comparable<Number>, pero no al revés.

Andrew Feng
fuente
1
Creo que el punto más importante para una List<out T>declaración de visualización es que la outhace inmutable (en comparación con las colecciones mutables, que no tienen salida). Puede ser útil mencionarlo y enfatizarlo en la respuesta. La conversión implícita es una consecuencia de este en lugar del punto principal (dado que no se puede escribir en List <Number>, es seguro tenerlo como referencia a List <Double>).
minsk
39
Lo siento, pero todavía no pude entender.
Akshay Taru
2
@minsk Sin embargo, la outparte no es lo que lo hace Listinmutable. Puede crear fácilmente su propia List<out T>interfaz que tenga un clear()método, ya que no requeriría ningún argumento.
Nick Lowery
este es uno de esos temas que probablemente desee obtener hasta que realmente lo necesite en algún lugar de su código.
lasec0203
109
List<out T> is like List<? extends T> in Java

y

List<in T> is like List<? super T> in Java

Por ejemplo, en Kotlin puedes hacer cosas como

 val value : List<Any> = listOf(1,2,3)
//since List signature is List<out T> in Kotlin
Dmitry Borodin
fuente
1
Esta respuesta es al revés. List<out T>significa que puede hacerlo val list: List<Number> = listOf<Int>()porque Intes un tipo derivado de Number. El Java equivalente seríaList<? extends Number> list = new ArrayList<Integer>();
Nick Lowery
Buen punto, en Java es "? Extiende T", no "? Super T". Fijo. No mencioné que definimos Varianza en lugares diferentes para mantener la respuesta simple. Todo el mundo puede acudir a la documentación oficial para conocer todos los detalles. Así que no entendí qué querías decir con "la respuesta es al revés".
DmitryBorodin
4

Consulte el manual de Kotlin.

El List<out T>tipo Kotlin es una interfaz que proporciona operaciones de solo lectura como tamaño, obtención, etc. Como en Java, hereda Collection<T>y que a su vez hereda Iterable<T>. La MutableList<T>interfaz agrega los métodos que cambian la lista . Este patrón también es válido para Set<out T>/MutableSet<T>yMap<K, out V>/MutableMap<K, V>

Y esto,

En Kotlin, hay una forma de explicar este tipo de cosas al compilador. Esto se llama variación del sitio de declaración: podemos anotar el parámetro de tipo T de Fuente para asegurarnos de que solo se devuelva (produzca) de miembros de Source<T>, y nunca se consuma. Para hacer esto, proporcionamos el modificador de salida:

> 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
>     // ... }

La regla general es: cuando un parámetro Tde tipo de una clase Cse declara out, puede ocurrir solo en out-position en los miembros de C, pero a cambioC<Base> puede ser un supertipo deC<Derived> .

En "palabras inteligentes", dicen que la clase Ces covariante en el parámetro T, o que Tes un parámetro de tipo covariante. Puede pensar en C como un productor de T y NO como un consumidor de T. El modificador out se denomina anotación de varianza y, dado que se proporciona en el sitio de declaración de parámetros de tipo, hablamos de varianza de sitio de declaración. Esto contrasta con la variación del sitio de uso de Java, donde los comodines en los usos de tipos hacen que los tipos sean covariantes.

LF00
fuente
3

Recuerda así:

ines "for in put": quieres poner (escribir) algo en él (por lo que es un "consumidor")

outes "para sacar ": quieres sacar (leer) algo (así que es un "productor")

Si eres de Java,

<in T>es para entrada, por lo que es como <? super T>(consumidor)

<out T>es para salida, entonces es como <? extends T>(productor)

starriet
fuente