Kotlin Academy · Ders

Bildirim Yerinde Varyans: in ve out

Kovaryant (out) ve kontravaryant (in) tür parametrelerini doğru kullanın.

2. ders / 413 adım

Bildirim Yerinde Varyans: in ve out, CoddyKit'te ücretsiz bir Kotlin Academy dersidir. Bu, 4 dersinin 2. dersidir. Aşağıdan dersin tamamını ücretsiz okuyabilir, sonra tarayıcıda yerleşik kod editörü ve 7/24 yapay zeka koçu ile uygulamalı olarak pratik yapabilirsin. Bu, Kotlin Academy öğrenme yolunun bir parçasıdır ve ilerlemeniz web ve CoddyKit uygulaması arasında senkronize olur. Kotlin Academy kursu toplamda 4 dersten oluşur.

Varyans Sorunu

Kotlin'de List<String>, List out T ile tanımlandığı için List<Any>'nin bir alt türüdür. Varyans açıklamaları olmasaydı bu ilişki kurulamazdı.

val strings: List<String> = listOf("a", "b")
val anys: List<Any> = strings  // OK because List<out T>
// MutableList<String> is NOT a subtype of MutableList<Any>:
// val m: MutableList<Any> = mutableListOf("x") // compile error
fun main() { println(anys) }

out ile Kovaryans

out T, sınıfın yalnızca T değerleri üretebileceği (bunları döndürebileceği), hiçbir zaman tüketemeyeceği anlamına gelir. Bu, Producer<Dog>'u Producer<Animal>'ın bir alt türü yapar.

interface Producer<out T> {
    fun produce(): T
}
class DogProducer : Producer<String> {
    override fun produce() = "Woof!"
}
fun sound(p: Producer<Any>) = println(p.produce())
fun main() {
    val dog = DogProducer()
    sound(dog)  // OK: Producer<String> is a subtype of Producer<Any>
}

in ile Kontravaryans

in T, sınıfın yalnızca T değerlerini tüketebileceği (bunları parametre olarak kabul edebileceği), hiçbir zaman üretemeyeceği anlamına gelir. Bu, Consumer<Animal>'ı Consumer<Dog>'un bir alt türü yapar.

interface Consumer<in T> {
    fun consume(item: T)
}
class Printer : Consumer<Any> {
    override fun consume(item: Any) = println(item)
}
fun feedDog(consumer: Consumer<String>) = consumer.consume("Dog")
fun main() {
    val printer = Printer()
    feedDog(printer)  // OK: Consumer<Any> is a subtype of Consumer<String>
}

out Kısıtlaması: in Konumunda Kullanılamaz

out T kullanıldığında T, parametre (in) konumunda yer alamaz. Derleyici bunu zorunlu kılar.

interface ReadOnly<out T> {
    fun get(): T          // OK: out position
    // fun set(t: T) {}  // Error: T in in-position violates out variance
}
class Box<out T>(private val value: T) : ReadOnly<T> {
    override fun get() = value
}
fun main() {
    val box: ReadOnly<Any> = Box<String>("hello")
    println(box.get())
}

in Kısıtlaması: out Konumunda Kullanılamaz

in T kullanıldığında T, dönüş (out) konumunda yer alamaz.

interface WriteOnly<in T> {
    fun set(t: T)        // OK: in position
    // fun get(): T {}  // Error: T in out-position violates in variance
}
class Sink<in T> : WriteOnly<T> {
    override fun set(t: T) = println("Received: $t")
}
fun main() {
    val sink: WriteOnly<String> = Sink<Any>()
    sink.set("hello")
}

Kotlin Standart Kitaplığı Örnekleri

Comparable<in T> kontravaryanttır: Comparable<Number>, her Number alt türünü karşılaştırabilir. List<out T> kovaryanttır: Kedilerden oluşan bir liste, hayvanlardan oluşan bir listedir.

fun sortNumbers(list: List<Number>) = list.sortedWith(compareBy { it.toDouble() })
fun main() {
    val ints: List<Int> = listOf(3, 1, 2)
    val sorted = sortNumbers(ints)  // OK: List<Int> is List<Number>
    println(sorted)
}

Değişmezlik: MutableList

MutableList<T> değişmezdir: T üretebildiği ve tüketebildiği için farklı T türleri arasında alt tür ilişkisi kurulamaz.

fun addNumber(list: MutableList<Number>) { list.add(1.5) }
fun main() {
    val ints = mutableListOf<Int>(1, 2)
    // addNumber(ints) // compile error: MutableList<Int> is not MutableList<Number>
    val nums = mutableListOf<Number>(1, 2)
    addNumber(nums)   // OK
    println(nums)
}

Alternatif Olarak Kullanım Noktası Varyansı

Sınıfı değiştiremediğinizde kullanım noktası varyansını kullanın: Bir türü kovaryant olarak yansıtmak için çağrı noktasında out belirtin.

fun copy(from: MutableList<out Any>, to: MutableList<Any>) {
    for (item in from) to.add(item)
}
fun main() {
    val src = mutableListOf("a", "b", "c")
    val dest = mutableListOf<Any>()
    copy(src, dest)
    println(dest)
}

Uygulama: Repository Kalıbı

Veri akışını temiz biçimde modellemek için salt okunur depolarda kovaryansı, salt yazılabilir veri hedeflerinde kontravaryansı kullanın.

interface Repository<out T> {
    fun findAll(): List<T>
    fun findById(id: Int): T?
}
interface Writer<in T> {
    fun save(entity: T)
}
interface ReadWriteRepo<T> : Repository<T>, Writer<T>
// ReadWriteRepo<User> is neither sub nor super of ReadWriteRepo<Admin>

Varyans Seçim Rehberi

Varyansı T'nin nasıl kullanıldığına göre seçin: out = üretici (yalnızca T döndürür), in = tüketici (yalnızca T kabul eder), değişmez = her ikisi (MutableList, Channel).

// Quick mental model:
// out T: source/producer  — List, Flow, Sequence
// in  T: sink/consumer    — Comparable, Continuation
// invariant: read+write   — MutableList, Channel, MutableStateFlow
fun main() {
    val nums: List<Number> = listOf(1, 2, 3)  // List is out
    println(nums)
}

out İşlevi İçeren Değişmez Sınıf

Değişmez bir sınıfta bile belirli işlev parametreleri için kullanım noktasında out kullanabilirsiniz.

class Stack<T>(private val items: MutableList<T> = mutableListOf()) {
    fun push(item: T) = items.add(item)
    fun pop(): T? = items.removeLastOrNull()
}
fun printAll(stack: Stack<out Any>) {
    // can only read, not write
    println(stack.pop())
}
fun main() {
    val s = Stack<String>()
    s.push("hello")
    printAll(s)
}

Kısa Kontrol

Bir tür parametresindeki out T ne anlama gelir?

Özet

out T (kovaryans), değerler üretilirken alt tür ilişkisine izin verir. in T (kontravaryans), değerler tüketilirken alt tür ilişkisine izin verir. Değişmez türler (hem okuma hem yazma yapanlar), farklı T türleri arasında alt tür ilişkisine sahip değildir.

Başlamak ücretsiz

Yapay zeka eğitmeniyle Kotlin öğren — ücretsiz

Tarayıcında gerçek kod yaz ve çalıştır, 7/24 yapay zeka eğitmeninden anında yardım al; web'de ya da uygulamada kaldığın yerden devam et.

Kurslar
51
Dersler
203

Sıkça Sorulan Sorular

“Bildirim Yerinde Varyans: in ve out” dersi ücretsiz mi?

Evet — “Bildirim Yerinde Varyans: in ve out” dersin tüm metni burada web'de ücretsiz olarak okunabilir. Etkileşimli olarak pratik yapmak (yerleşik kod editörü ve 7/24 yapay zeka koçu) ve Kotlin Academy kursunun geri kalanını açmak için CoddyKit PRO'ya yükselt. Kotlin Academy kursu toplamda 4 dersten oluşur.

“Bildirim Yerinde Varyans: in ve out” dersinde ne öğreneceğim?

Kovaryant (out) ve kontravaryant (in) tür parametrelerini doğru kullanın. Kotlin Academy ile uygulamalı kodu tarayıcıda doğrudan çalıştırarak pratik yaparsın ve 7/24 yapay zeka koçu dersi çalışırken sorularını yanıtlar.

Kotlin Academy öğrenmeye başlamak için deneyim gerekli mi?

Önceden deneyim gerekmez. CoddyKit'te Kotlin Academy, başlangıçtan ileri seviyeye kadar yapılandırıldığı için buradan başlayabilir veya başından başlayıp kendi hızında ilerleme yapabilirsin. Bu, 4 dersinin 2. dersidir.

“Bildirim Yerinde Varyans: in ve out” dersi ne kadar sürer?

Çoğu CoddyKit dersi yaklaşık 5–10 dakika sürer. Her biri kısa ve etkileşimli olduğu için sabit ilerleme yaparsın ve web ile uygulama arasında tam olarak bıraktığın yerden devam edebilirsin.

Bu Kotlin Academy dersinde kod yazıp çalıştırabilir miyim?

Evet. Her Kotlin Academy dersi yerleşik bir kod editörü içerir, bu sayede tarayıcıda gerçek kod yazıp çalıştırabilir ve anlık yapay zeka geri bildirimi alırsın — yerel kurulum gerekli değildir.

Bu kursun tüm dersleri

  1. where ile Genel İşlevler ve Tür Kısıtlamaları
  2. Bildirim Yerinde Varyans: in ve out
  3. Yıldız Projeksiyonu ve * Ne Zaman Kullanılır
  4. Tür Silinmesi ve reified Tür Parametreleri
← Kotlin Academy Sayfasına Dön