0Pricing
Kotlin Academy · Lekcja

Wariancja w miejscu użycia

Projekcje typów

Wariancja w miejscu użycia to bezpłatna lekcja Kotlin Academy na CoddyKit. To lekcja 3 z 4. Możesz przeczytać całą lekcję poniżej za darmo — a potem ćwiczyć ją interaktywnie w przeglądarce z wbudowanym edytorem kodu i tutorem AI dostępnym 24/7. To część ścieżki edukacyjnej Kotlin Academy, a Twój postęp synchronizuje się między webem a aplikacją CoddyKit. Kurs Kotlin Academy zawiera 4 lekcji w sumie.

Wariancja w miejscu użycia

Czasami klasa generyczna jest ogólnie inwariantna, ale konkretna funkcja tylko produkuje typ albo tylko go przyjmuje. Wariancja w miejscu użycia, czyli projekcje typów, stosuje out lub in bezpośrednio w miejscu użycia typu.

Dlaczego stosować wariancję w miejscu użycia

Klasy inwariantnej, takiej jak MutableList<T>, nie można zadeklarować jako kowariantnej, ponieważ zarówno odczytuje ona T, jak i zapisuje T. Jednak konkretna funkcja może tylko odczytywać dane z takiej klasy, a projekcje pozwalają bezpiecznie to wyrazić.

Projekcja out

Podanie Array<out T> jako typu parametru tworzy widok kowariantny: można odczytywać wartości T, ale nie można ich zapisywać. Dzięki temu można przekazać Array<String> tam, gdzie oczekiwany jest typ Array<out Any>.

fun printArray(items: Array<out Any>) {
    for (item in items) println(item)
}

fun main() {
    val names: Array<String> = arrayOf("Ann", "Bob")
    printArray(names)
}

Tylko odczyt

W przypadku projekcji out kompilator zezwala na odczyt, czyli operację wyjściową, ale zabrania zapisu, czyli operacji wejściowej, ponieważ zapis mógłby naruszyć bezpieczeństwo typów oryginalnej tablicy.

Projekcja in

Podanie Array<in T> tworzy widok kontrawariantny: można zapisywać do niego wartości T, ale odczytywane wartości mają typ Any?. Dzięki temu można przyjmować tablice typu T lub dowolnego nadtypu.

fun fill(dest: Array<in Int>, value: Int) {
    for (i in dest.indices) dest[i] = value
}

fun main() {
    val numbers: Array<Number> = arrayOf(0, 0, 0)
    fill(numbers, 7)
    println(numbers.toList())
}

Tylko zapis

W przypadku projekcji in można zapisywać wartości typu T, czyli dane wejściowe, ale podczas odczytu typ elementu jest widziany jako typ najwyższy, ponieważ rzeczywisty typ elementu może być dowolnym nadtypem.

Projekcje a wariancja w miejscu deklaracji

Wariancja w miejscu deklaracji, na przykład class Box<out T>, obowiązuje wszędzie tam, gdzie używana jest klasa. Projekcje w miejscu użycia, na przykład Box<out T> jako typ parametru, obowiązują tylko w jednym konkretnym miejscu. Projekcji należy używać, gdy sama klasa musi pozostać inwariantna.

Projekcja gwiazdkowa

Jeśli argument typu w ogóle nie ma znaczenia, należy użyć projekcji gwiazdkowej *. List<*> oznacza listę pewnego nieznanego typu; elementy można odczytywać jako typ będący ograniczeniem górnym, ale nie można bezpiecznie do niej zapisywać.

fun printSize(collection: List<*>) {
    println("Size: ${collection.size}")
}

fun main() {
    printSize(listOf(1, 2, 3))
    printSize(listOf("a", "b"))
}

Ograniczenia projekcji gwiazdkowej

Za pomocą * nadal można wywoływać elementy niezależne od typu, takie jak size, oraz odczytywać elementy jako Any?, ale nie można dodawać elementów, ponieważ rzeczywisty typ jest nieznany.

fun main() {
    val unknown: List<*> = listOf("x", "y")
    val first: Any? = unknown.first()
    println(first)
}

Wybór projekcji

Należy używać out T, gdy funkcja tylko odczytuje dane, in T, gdy tylko je zapisuje, oraz *, gdy dokładny typ nie ma znaczenia. Projekcje te pozwalają elastycznie i bezpiecznie typowo korzystać z klas niezmienniczych.

Związek z symbolami wieloznacznymi w Javie

Projekcje Kotlinu out T i in T odpowiadają symbolom wieloznacznym Javy ? extends T i ? super T. Jeśli znają Państwo typy generyczne w Javie, projekcje będą znajome.

Szybkie sprawdzenie

Co można zrobić z parametrem typu Array<out Any>?

Podsumowanie

Wariancja w miejscu użycia stosuje projekcje out (tylko do odczytu) lub in (tylko do zapisu) w konkretnym miejscu użycia, a * oznacza projekcję gwiazdkową używaną, gdy typ jest nieznany. Dzięki temu klasy niezmiennicze stają się elastyczne bez zmieniania ich deklaracji. Następnie ograniczą Państwo parametry typów za pomocą ograniczeń generycznych.

Często zadawane pytania

Czy lekcja „Wariancja w miejscu użycia” jest bezpłatna?

Tak — pełny tekst „Wariancja w miejscu użycia” jest dostępny za darmo tutaj w sieci. Aby ćwiczyć ją interaktywnie (wbudowany edytor kodu i tutor AI dostępny 24/7) i odblokować resztę kursu Kotlin Academy, przejdź na CoddyKit PRO. Kurs Kotlin Academy zawiera 4 lekcji w sumie.

Co nauczysz się w „Wariancja w miejscu użycia”?

Projekcje typów Ćwiczysz Kotlin Academy z praktycznym kodem, który uruchamiasz bezpośrednio w przeglądarce, a tutor AI dostępny 24/7 odpowiada na Twoje pytania podczas pracy nad lekcją.

Czy potrzebuję doświadczenia, aby zacząć Kotlin Academy?

Nie wymagamy żadnego doświadczenia. Kotlin Academy w CoddyKit jest strukturyzowany dla początkujących i zaawansowanych użytkowników, więc możesz zacząć tutaj lub od początku i uczyć się w swoim tempie. To lekcja 3 z 4.

Ile czasu zajmuje lekcja „Wariancja w miejscu użycia”?

Większość lekcji CoddyKit trwa około 5–10 minut. Każda lekcja to mały, interaktywny krok, dzięki czemu robisz systematyczne postępy i zawsze wracasz dokładnie do tego samego miejsca — na webie i w aplikacji.

Czy mogę pisać i uruchamiać kod w tej lekcji Kotlin Academy?

Tak. Każda lekcja Kotlin Academy zawiera wbudowany edytor kodu, więc piszesz i uruchamiasz prawdziwy kod bezpośrednio w przeglądarce i od razu otrzymujesz sprzężenie zwrotne od AI — bez konfiguracji na komputerze.

Wszystkie lekcje w tym kursie

  1. Funkcje i klasy generyczne
  2. Wariancja w miejscu deklaracji
  3. Wariancja w miejscu użycia
  4. Ograniczenia typów generycznych
← Powrót do Kotlin Academy