Sobes.tech
Middle

Как да работите с обобщени типове в Kotlin?

sobes.tech AI

Отговор от 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 типове (reified): Достъпни са само за inline функции. Позволяват запазване на информация за типа на параметъра по време на изпълнение.
    inline fun <reified T> checkType(value: Any) { // T - reified тип
        if (value is T) {
            println("Value is of type T")
        } else {
            println("Value is not of type T")
        }
    }