Variantie op declaratieplaats
in en out
Variantie op declaratieplaats is een gratis Kotlin Academy-les op CoddyKit. Dit is les 2 van 4. Je kunt 3 lessen uit dit leerpad gratis volledig lezen — daarna ontgrendelt CoddyKit PRO alle lessen, plus praktische oefeningen met een ingebouwde code-editor en een AI-tutor die 24/7 beschikbaar is. Deze les maakt deel uit van het leertraject Kotlin Academy. Je voortgang wordt gesynchroniseerd op het web en in de CoddyKit-app. De cursus Kotlin Academy bevat in totaal 4 lessen.
Het variantieprobleem
Is een List<String> een soort List<Any>? Soms wel en soms niet. Variantie beschrijft hoe generieke typen zich tot elkaar verhouden wanneer hun typeparameters aan elkaar gerelateerd zijn. Kotlin gebruikt out en in om dit uit te drukken.
Standaard invariantie
Generieke typen zijn standaard invariant: Box<String> is GEEN Box<Any>, ook al is String een subtype van Any. Zo worden onveilige bewerkingen voorkomen.
class Box<T>(val value: T)
fun main() {
val strBox = Box("hi")
// val anyBox: Box<Any> = strBox // would not compile
println(strBox.value)
}Covariantie met out
Door een typeparameter te markeren met out maak je deze covariant: Producer<String> wordt een subtype van Producer<Any>. Het type mag alleen op uitvoerposities voorkomen, zoals in retourtypen.
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())
}Waarom out veilig is
Als een klasse alleen T produceert, dus retourneert, en het nooit verwerkt, is het veilig om een Producer<String> te behandelen als een Producer<Any>, omdat elke String die wordt geretourneerd ook een Any is.
out in de standaardbibliotheek
De alleen-lezenvariant List<out E> van Kotlin is covariant. Daarom kan een List<String> worden gebruikt waar een List<Any> wordt verwacht.
fun printAll(items: List<Any>) {
items.forEach { println(it) }
}
fun main() {
val names: List<String> = listOf("Ann", "Bob")
printAll(names)
}Contravariantie met in
Door een typeparameter te markeren met in maak je deze contravariant: Consumer<Any> wordt een subtype van Consumer<String>. Het type mag alleen op invoerposities voorkomen, zoals in parameters.
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")
}Waarom in veilig is
Een consument die Any accepteert, kan zeker ook een String accepteren. Daarom kan een Consumer<Any> overal worden gebruikt waar een Consumer<String> nodig is.
Het PECS-ezelsbruggetje
Onthoud: een producent breidt uit, een consument gebruikt een supertype. In Kotlin-termen betekent dit: out voor producenten (uitvoer) en in voor consumenten (invoer). Een type dat alleen T uitvoert, gebruikt out; een type dat alleen T invoert, gebruikt in.
in en out combineren
Een typeparameter die zowel voor invoer als uitvoer wordt gebruikt, zoals in een veranderlijke lijst, moet invariant blijven. Typen van Function laten beide zien: parameters zijn in en het retourtype is out.
fun main() {
val f: (Number) -> Int = { it.toInt() }
val g: (Int) -> Number = f
println(g(3.0.let { Number::class; 5 }))
}Variantie op declaratieplaats betekent één plek
Variantie op declaratieplaats wordt één keer gedeclareerd, op de klasse zelf met in of out. Elk gebruik van de klasse krijgt de variantie vervolgens automatisch, anders dan in Java, waar je de jokertekens bij elk gebruik opnieuw opgeeft.
in of out kiezen
Vraag jezelf af: produceert deze klasse alleen T, dus gebruik je out, verwerkt ze alleen T, dus gebruik je in, of doet ze beide, dus laat je haar invariant? Als je de modificator afstemt op de rol, worden je generieke typen flexibel en veilig.
Korte controle
Wat geeft de modificator out aan?
Samenvatting
Generieke typen zijn standaard invariant. Gebruik out voor covariantie wanneer een type alleen waarden produceert, en in voor contravariantie wanneer het alleen waarden verwerkt. Onthoud: producenten gebruiken out en consumenten gebruiken in. Vervolgens pas je variantie toe op de plek waar je een type gebruikt, met typeprojecties.
Leer Kotlin met een AI-tutor — gratis
Schrijf echte code en voer die uit in je browser, krijg direct hulp van een AI-tutor die 24/7 beschikbaar is en ga verder waar je gebleven bent op het web of in de app.
- Cursussen
- 51
- Lessen
- 203
Veelgestelde vragen
Is de les “Variantie op declaratieplaats” gratis?
Ja — je kunt hier op het web alle 3 lessen van het leerpad Kotlin Academy, waaronder “Variantie op declaratieplaats”, gratis volledig lezen. Daarna ontgrendelt CoddyKit PRO alle lessen, plus interactieve oefeningen met een ingebouwde code-editor en een AI-tutor die 24/7 beschikbaar is. De cursus Kotlin Academy bevat in totaal 4 lessen.
Wat leer ik in “Variantie op declaratieplaats”?
in en out Je oefent met Kotlin Academy door code rechtstreeks in de browser uit te voeren. Een AI-begeleider die 24/7 beschikbaar is beantwoordt je vragen terwijl je de les doorwerkt.
Heb ik ervaring nodig om met Kotlin Academy te beginnen?
Ervaring vooraf is niet nodig. Kotlin Academy op CoddyKit is opgebouwd voor beginners tot gevorderden, zodat je hier of bij het begin kunt starten en in je eigen tempo kunt leren. Dit is les 2 van 4.
Hoe lang duurt de les “Variantie op declaratieplaats”?
De meeste lessen van CoddyKit duren ongeveer 5–10 minuten. Elke les is kort en interactief, zodat je gestaag vooruitgaat en op het web en in de app precies verdergaat waar je was gebleven.
Kan ik code schrijven en uitvoeren in deze les over Kotlin Academy?
Ja. Elke les over Kotlin Academy bevat een ingebouwde code-editor, zodat je rechtstreeks in je browser echte code kunt schrijven en uitvoeren en direct feedback van AI krijgt — lokale installatie is niet nodig.
Alle lessen in deze cursus
- Generieke functies en klassen
- Variantie op declaratieplaats
- Variantie op gebruiksplaats
- Beperkingen voor generieke typen