Kotlin Academy · Lektion

Varians på deklarationsstedet

in og out

Lektion 2 af 413 trin

Varians på deklarationsstedet er en gratis Kotlin Academy-lektion på CoddyKit. Dette er lektion 2 af 4. Du kan læse alle 3 lektioner i dette læringsspor gratis i deres fulde længde — derefter låser CoddyKit PRO alle lektioner op samt praktiske øvelser med en indbygget kodeeditor og en AI-underviser døgnet rundt. Den er en del af læringsforløbet i Kotlin Academy, og dine fremskridt synkroniseres på tværs af nettet og CoddyKit-appen. Kotlin Academy-kurset indeholder 4 lektioner i alt.

Variansproblemet

Er en List<String> en slags List<Any>? Nogle gange ja, andre gange nej. Varians beskriver, hvordan generiske typer hænger sammen, når deres typeparametre hænger sammen. Kotlin bruger out og in til at udtrykke dette.

Invarians som standard

Som standard er generiske typer invariante: Box<String> er IKKE en Box<Any>, selv om String er en subtype af Any. Det forhindrer usikre operationer.

class Box<T>(val value: T)

fun main() {
    val strBox = Box("hi")
    // val anyBox: Box<Any> = strBox // would not compile
    println(strBox.value)
}

Kovarians med out

Når du markerer en typeparameter med out, bliver den kovariant: Producer<String> bliver en subtype af Producer<Any>. Typen må kun optræde i positioner, der leverer uddata, f.eks. returtyper.

class Producer<out T>(private val item: T) {
    fun produce(): T = item
}

fun main() {
    val strProducer: Producer<String> = Producer("hello")
    val anyProducer: Producer<Any> = strProducer
    println(anyProducer.produce())
}

Hvorfor out er sikkert

Hvis en klasse kun producerer eller returnerer T og aldrig modtager den, er det sikkert at behandle en Producer<String> som en Producer<Any>, fordi enhver String, den returnerer, også er en Any.

out i standardbiblioteket

Kotlins skrivebeskyttede List<out E> er kovariant, og derfor kan en List<String> bruges, hvor der forventes en List<Any>.

fun printAll(items: List<Any>) {
    items.forEach { println(it) }
}

fun main() {
    val names: List<String> = listOf("Ann", "Bob")
    printAll(names)
}

Kontravarians med in

Når du markerer en typeparameter med in, bliver den kontravariant: Consumer<Any> bliver en subtype af Consumer<String>. Typen må kun optræde i inddatapositioner, f.eks. parametre.

class Consumer<in T> {
    fun consume(item: T) {
        println("Consumed $item")
    }
}

fun main() {
    val anyConsumer: Consumer<Any> = Consumer()
    val strConsumer: Consumer<String> = anyConsumer
    strConsumer.consume("hi")
}

Hvorfor in er sikkert

En forbruger, der accepterer Any, kan naturligvis acceptere en String. Derfor kan en Consumer<Any> bruges overalt, hvor der er brug for en Consumer<String>.

Huskeregel for producenter og forbrugere

Husk producenter leverer, forbrugere modtager, eller med Kotlins termer: out til producenter, der leverer uddata, og in til forbrugere, der modtager inddata. En type, der kun leverer T, bruger out; en type, der kun modtager T, bruger in.

Kombination af in og out

En typeparameter, der bruges til både inddata og uddata, som i en foranderlig liste, skal forblive invariant. Function-typer viser begge dele: parametre er in, og returværdien er out.

fun main() {
    val f: (Number) -> Int = { it.toInt() }
    val g: (Int) -> Number = f
    println(g(3.0.let { Number::class; 5 }))
}

Varians ved deklarationsstedet betyder ét sted

Varians ved deklarationsstedet erklæres én gang på selve klassen med in/out. Alle anvendelser af klassen får derefter automatisk denne varians, i modsætning til Java, hvor du gentager jokertegnene ved hver anvendelse.

Valg mellem in og out

Spørg: Producerer denne klasse kun T, så du skal bruge out, modtager den kun T, så du skal bruge in, eller gør den begge dele, så den skal forblive invariant? Når modifikatoren passer til rollen, bliver dine generiske typer fleksible og sikre.

Hurtig kontrol

Hvad angiver modifikatoren out?

Opsummering

Generiske typer er som standard invariante. Brug out til kovarians, når en type kun producerer værdier, og in til kontravarians, når den kun modtager værdier. Husk, at producenter bruger out, og forbrugere bruger in. Nu skal du anvende varians på anvendelsesstedet med typeprojektioner.

Gratis at komme i gang

Lær Kotlin med en AI-underviser — gratis

Skriv og kør rigtig kode i din browser, få øjeblikkelig hjælp fra en AI-underviser døgnet rundt, og fortsæt, hvor du slap, på web eller i appen.

Kurser
51
Lektioner
203

Ofte stillede spørgsmål

Er lektionen “Varians på deklarationsstedet” gratis?

Ja — alle 3 lektioner i læringssporet Kotlin Academy, inklusive “Varians på deklarationsstedet”, kan læses gratis i deres fulde længde her på webstedet. Derefter låser CoddyKit PRO alle lektioner op samt interaktive øvelser med en indbygget kodeeditor og en AI-underviser døgnet rundt. Kotlin Academy-kurset indeholder 4 lektioner i alt.

Hvad lærer jeg i “Varians på deklarationsstedet”?

in og out Du øver dig i Kotlin Academy med praktisk kode, som du kører direkte i browseren, og en AI-vejleder døgnet rundt besvarer dine spørgsmål, mens du arbejder dig gennem lektionen.

Skal jeg have erfaring for at begynde på Kotlin Academy?

Der kræves ingen tidligere erfaring. Kotlin Academy på CoddyKit er tilrettelagt for både begyndere og øvede, så du kan starte her eller fra begyndelsen og lære i dit eget tempo. Dette er lektion 2 af 4.

Hvor lang tid tager lektionen “Varians på deklarationsstedet”?

De fleste CoddyKit-lektioner tager cirka 5–10 minutter. Hver lektion er kort og interaktiv, så du gør løbende fremskridt og kan fortsætte, hvor du slap – på både web og app.

Kan jeg skrive og køre kode i denne Kotlin Academy-lektion?

Ja. Alle Kotlin Academy-lektioner har en indbygget kodeeditor, så du kan skrive og køre rigtig kode direkte i din browser og få øjeblikkelig feedback fra AI – uden lokal opsætning.

Alle lektioner i dette kursus

  1. Generiske funktioner og klasser
  2. Varians på deklarationsstedet
  3. Varians på anvendelsesstedet
  4. Generiske begrænsninger
← Tilbage til Kotlin Academy