0Pricing
Kotlin Academy · Lekcja

Funkcje generyczne i ograniczenia typów za pomocą where

Pisz funkcje generyczne z pojedynczymi i wieloma ograniczeniami typów.

Funkcje generyczne i ograniczenia typów za pomocą where to bezpłatna lekcja Kotlin Academy na CoddyKit. To lekcja 1 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.

Podstawy funkcji generycznych

Funkcje generyczne używają parametrów typów umieszczonych w nawiasach ostrych przed nazwą funkcji. Parametru typu można używać w typach parametrów i typach zwracanych.

fun <T> identity(value: T): T = value
fun <T> listOf2(a: T, b: T): List<T> = listOf(a, b)
fun main() {
    println(identity(42))       // 42
    println(identity("hello"))  // hello
    println(listOf2(1, 2))      // [1, 2]
}

Górne ograniczenia za pomocą ograniczenia :

Ogranicz parametr typu za pomocą górnego ograniczenia, używając :. Typ musi być podtypem ograniczenia.

fun <T : Comparable<T>> max(a: T, b: T): T = if (a >= b) a else b
fun main() {
    println(max(3, 7))          // 7
    println(max("apple", "banana")) // banana
    // max(listOf(1), listOf(2)) // error: List is not Comparable
}

Górne ograniczenie dopuszczające null

Domyślnym górnym ograniczeniem jest Any? (dopuszczające wartość null). Użyj T : Any, aby wykluczyć null.

fun <T : Any> notNull(value: T?): T {
    return value ?: throw IllegalArgumentException("Value is null")
}
fun main() {
    println(notNull("hello"))  // hello
    try { notNull(null) } catch (e: Exception) { println(e.message) }
}

Wiele ograniczeń za pomocą where

Użyj klauzuli where, aby zastosować wiele ograniczeń do jednego parametru typu.

fun <T> process(item: T): String
        where T : Comparable<T>, T : CharSequence {
    return "Length=${item.length}, sorted=${item > "a"}"
}
fun main() {
    println(process("kotlin")) // Length=6, sorted=true
    // process(42) // error: Int doesn't implement CharSequence
}

where w klasie

Klauzula where działa również w przypadku parametrów typów na poziomie klasy.

class SortedContainer<T>(private val items: MutableList<T> = mutableListOf())
        where T : Comparable<T>, T : Any {
    fun add(item: T) { items.add(item); items.sort() }
    fun top(): T? = items.lastOrNull()
}
fun main() {
    val c = SortedContainer<Int>()
    c.add(5); c.add(2); c.add(8)
    println(c.top()) // 8
}

Generyczne funkcje rozszerzające

Funkcje rozszerzające również mogą mieć parametry typów, dzięki czemu są dostępne dla określonych typów generycznych.

fun <T : Comparable<T>> List<T>.second(): T? {
    return if (size >= 2) this[1] else null
}
fun main() {
    println(listOf(10, 20, 30).second()) // 20
    println(listOf("a").second())        // null
}

Parametr typu w typie zwracanym

Funkcje generyczne mogą wywnioskować typ z kontekstu, dzięki czemu w miejscu wywołania nie trzeba jawnie podawać argumentów typów.

fun <T> MutableList<T>.popOrDefault(default: T): T {
    return if (isEmpty()) default else removeAt(lastIndex)
}
fun main() {
    val list = mutableListOf(1, 2, 3)
    println(list.popOrDefault(0)) // 3
    println(list.popOrDefault(0)) // 2
    println(mutableListOf<Int>().popOrDefault(-1)) // -1
}

Wielokrotnego użytku narzędzia generyczne

Funkcje generyczne pozwalają ponownie używać funkcji pomocniczych dla różnych typów bez powielania kodu.

fun <T> Iterable<T>.firstOrElse(default: T): T = firstOrNull() ?: default
fun <T, R : Comparable<R>> Iterable<T>.maxByOrElse(selector: (T) -> R, default: T): T =
    maxByOrNull(selector) ?: default
fun main() {
    println(listOf<String>().firstOrElse("fallback")) // fallback
    println(listOf("a","bbb","cc").maxByOrElse({ it.length }, "")) // bbb
}

Projekcja gwiazdkowa a ograniczony wildcard

Porównaj użycie ograniczonego parametru typu (przydatnego, gdy trzeba tworzyć lub przyjmować wartości typu T) z projekcją gwiazdkową (gdy typ jest nieznany).

fun <T : Number> sumList(list: List<T>): Double =
    list.sumOf { it.toDouble() }
// Star projection: read-only, type unknown
fun printAll(list: List<*>) = list.forEach { println(it) }
fun main() {
    println(sumList(listOf(1, 2, 3)))    // 6.0
    printAll(listOf("a", 1, true))       // a, 1, true
}

Generyczna zamiana elementów Pair

Prosta, ale obrazowa funkcja generyczna, która odwraca składowe obiektu Pair.

fun <A, B> Pair<A, B>.swap(): Pair<B, A> = Pair(second, first)
fun main() {
    val pair = Pair("hello", 42)
    val swapped = pair.swap()
    println(swapped) // (42, hello)
}

Praktyka: generyczne rozpakowywanie Result

Użyj ograniczonych typów generycznych, aby napisać funkcję pomocniczą mapującą obiekt Result<T> za pomocą transformacji o określonym typie.

fun <T : Any, R : Any> Result<T>.mapNotNull(transform: (T) -> R?): Result<R> {
    return fold(
        onSuccess = { v ->
            val r = transform(v)
            if (r != null) Result.success(r) else Result.failure(NoSuchElementException())
        },
        onFailure = { Result.failure(it) }
    )
}
fun main() {
    val r = Result.success("123")
    val n = r.mapNotNull { it.toIntOrNull() }
    println(n) // Success(123)
}

Szybkie sprawdzenie

Jak zastosować wiele ograniczeń do jednego parametru typu?

Podsumowanie

Funkcje generyczne używają parametrów typów do tworzenia wielokrotnego użytku i bezpiecznego typowo kodu. Użyj : dla pojedynczego ograniczenia lub where dla wielu ograniczeń. Kompilator Kotlin wymusza przestrzeganie ograniczeń w miejscu wywołania.

Często zadawane pytania

Czy lekcja „Funkcje generyczne i ograniczenia typów za pomocą where” jest bezpłatna?

Tak — pełny tekst „Funkcje generyczne i ograniczenia typów za pomocą where” 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 „Funkcje generyczne i ograniczenia typów za pomocą where”?

Pisz funkcje generyczne z pojedynczymi i wieloma ograniczeniami 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 1 z 4.

Ile czasu zajmuje lekcja „Funkcje generyczne i ograniczenia typów za pomocą where”?

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 generyczne i ograniczenia typów za pomocą where
  2. Wariancja deklarowana w miejscu deklaracji: in i out
  3. Projekcja gwiazdkowa i kiedy używać *
  4. Wymazywanie typów i parametry typów reified
← Powrót do Kotlin Academy