Kotlin Academy · Урок

Обобщённые функции и ограничения типов с where

Пишите обобщённые функции с одним или несколькими ограничениями типов.

Урок 1 из 413 шагов

«Обобщённые функции и ограничения типов с where» — бесплатный урок Kotlin Academy на CoddyKit. Это урок 1 из 4. Ты можешь прочитать весь урок бесплатно ниже — а потом практиковать его прямо в браузере с встроенным редактором кода и ИИ-репетитором 24/7. Это часть пути обучения Kotlin Academy, и твой прогресс синхронизируется между веб-версией и приложением CoddyKit. Курс Kotlin Academy содержит 4 уроков всего.

Основы обобщённых функций

Обобщённые функции используют параметры типа в угловых скобках перед именем функции. Параметр типа можно использовать в типах параметров и возвращаемых значениях.

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]
}

Верхние границы с ограничением «:»

Ограничьте параметр типа верхней границей с помощью :. Тип должен быть подтипом этой границы.

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
}

Обнуляемая верхняя граница

По умолчанию верхняя граница — Any? (допускающая пустое значение). Используйте T : Any, чтобы исключить пустое значение.

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) }
}

Несколько ограничений с where

Используйте предложение where, чтобы применить несколько ограничений к одному параметру типа.

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 в классе

Предложение where также работает с параметрами типа уровня класса.

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
}

Обобщённые функции-расширения

Функции-расширения также могут иметь параметры типа, благодаря чему их можно применять к определённым обобщённым типам.

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
}

Параметр типа в возвращаемой позиции

Обобщённые функции могут вывести тип из контекста, избавляя от необходимости явно указывать аргументы типа в месте вызова.

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
}

Повторно используемые обобщённые утилиты

Обобщённые функции позволяют повторно использовать вспомогательные функции для разных типов без дублирования.

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
}

Проекция со звёздочкой и ограниченный шаблон

Сравните использование ограниченного параметра типа (полезно, когда нужно создавать или принимать значения T) с проекцией со звёздочкой (когда тип неизвестен).

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
}

Обобщённая перестановка пары

Простая, но наглядная обобщённая функция, меняющая местами компоненты пары.

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)
}

Практика: извлечение значения из обобщённого результата

Используйте ограниченные обобщённые типы, чтобы написать утилиту, применяющую типизированное преобразование к Result<T>.

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)
}

Быстрая проверка

Как применить несколько ограничений к одному параметру типа?

Итоги

Обобщённые функции используют параметры типа для написания повторно используемого и типобезопасного кода. Используйте : для одной верхней границы или where для нескольких границ. Компилятор Kotlin проверяет ограничения в месте вызова.

Можно начать бесплатно

Изучай Kotlin с ИИ-репетитором — бесплатно

Пиши и запускай код прямо в браузере, получай мгновенную помощь от ИИ-репетитора 24/7 и продолжи учиться на сайте или в приложении.

Курсы
51
Уроки
203

Часто задаваемые вопросы

Урок «Обобщённые функции и ограничения типов с where» бесплатный?

Да — полный текст урока «Обобщённые функции и ограничения типов с where» бесплатно доступен здесь в веб-версии. Чтобы практиковать его интерактивно (встроенный редактор кода и ИИ-репетитор 24/7) и разблокировать остальной курс Kotlin Academy, подпишись на CoddyKit PRO. Курс Kotlin Academy содержит 4 уроков всего.

Чему я научусь в уроке «Обобщённые функции и ограничения типов с where»?

Пишите обобщённые функции с одним или несколькими ограничениями типов. Ты практикуешь Kotlin Academy с помощью реального кода, который запускаешь прямо в браузере, и ИИ-репетитор 24/7 отвечает на твои вопросы во время урока.

Нужен ли мне опыт, чтобы начать Kotlin Academy?

Предыдущий опыт не требуется. Kotlin Academy на CoddyKit структурирован для всех уровней — от новичков до продвинутых, поэтому ты можешь начать отсюда или с самого начала и учиться в своем темпе. Это урок 1 из 4.

Сколько времени занимает урок «Обобщённые функции и ограничения типов с where»?

Большинство уроков CoddyKit занимают около 5–10 минут. Каждый из них компактный и интерактивный, поэтому ты постоянно делаешь прогресс и продолжаешь с того же места в веб-версии и приложении.

Можно ли писать и запускать код в этом уроке Kotlin Academy?

Да. Каждый урок Kotlin Academy включает встроенный редактор кода, поэтому ты пишешь и запускаешь реальный код прямо в браузере и получаешь моментальную обратную связь от AI — локальная установка не требуется.

Все уроки этого курса

  1. Обобщённые функции и ограничения типов с where
  2. Вариативность на месте объявления: in и out
  3. Звёздная проекция и случаи применения *
  4. Стирание типов и параметры типов reified
← Назад к Kotlin Academy