Назад к вопросам
Middle
132
questionbank

Как работать с обобщенными типами (generics) в Kotlin?

Sobes Copilot

Получайте ответы в реальном времени

Ответ от нейросети

sobes.tech AI

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

Основные понятия и способы работы:

  • Объявление обобщенных классов и интерфейсов:
    class Box<T>(val item: T) // Обобщенный класс с параметром типа T
    interface MyList<E> { // Обобщенный интерфейс с параметром типа E
        fun add(element: E)
        fun get(index: Int): E
    }
    
  • Объявление обобщенных функций:
    fun <T> printAnything(value: T) { // Обобщенная функция с параметром типа T
        println(value)
    }
    
  • Создание экземпляров обобщенных типов:
    val intBox: Box<Int> = Box(123) // Указание конкретного типа (Int)
    val stringBox = Box("hello") // Компилятор выводит тип (String)
    
  • Вариантность: Позволяет определить, как работают подтипы с обобщенными типами.
    • Ковариантность (out): Позволяет использовать тип и его подтипы. Обозначается out. Пример: List<out Any> может содержать List<String>. Используется для типов, которые производят значения (например, чтение из коллекции).
      interface Producer<out T> { // out T - ковариантный параметр
           fun produce(): T
      }
      
    • Контравариантность (in): Позволяет использовать тип и его надтипы. Обозначается in. Пример: Comparator<in String> может работать с Comparator<Any>. Используется для типов, которые потребляют значения (например, запись в коллекцию).
      interface Consumer<in T> { // in T - контравариантный параметр
          fun consume(value: T)
      }
      
    • Инвариантность: Тип в обобщенном параметре должен быть точно таким же. Это поведение по умолчанию.
  • Ограничения типов (where): Позволяет ограничить тип параметром, чтобы он реализовал определенные интерфейсы или наследовался от определенного класса.
    fun <T : Comparable<T>> max(a: T, b: T): T { // T должен реализовывать Comparable
        return if (a > b) a else b
    }
    
    fun <T> process(item: T) where T : Runnable, T : Comparable<T> {
        item.run()
        // ... используем сравнимость
    }
    
  • Звездная (star) проекция (*): Используется, когда неважны конкретные аргументы типа. Аналогично <?> в Java.
    fun printList(list: List<*>) { // Можно принимать список любого типа
         for (item in list) {
             println(item)
         }
    }
    

Обобщенные типы в Kotlin используют стирание типов (type erasure), как и в Java. Информация о конкретных типах параметров теряется во время выполнения. Для работы с типами во время выполнения используются реифицированные (reified) типы.

  • Реифицированные типы (reified): Доступны только для inline функций. Позволяют сохранить информацию о типе параметра во время выполнения.
    inline fun <reified T> checkType(value: Any) { // T - реифицированный тип
        if (value is T) {
            println("Value is of type T")
        } else {
            println("Value is not of type T")
        }
    }