Sobes.tech
Middle

Ako pracovať s generickými typmi v Kotlin?

sobes.tech AI

Odpoveď od AI

Generické typy v Kotlin umožňujú vytvárať triedy, rozhrania a funkcie, ktoré pracujú s dátami rôznych typov, pričom zachovávajú typovú bezpečnosť počas kompilácie.

Hlavné pojmy a spôsoby práce:

  • Deklarácia generických tried a rozhraní:
    class Box<T>(val item: T) // Generická trieda s parametrom typu T
    interface MyList<E> { // Generické rozhranie s parametrom typu E
        fun add(element: E)
        fun get(index: Int): E
    }
    
  • Deklarácia generických funkcií:
    fun <T> printAnything(value: T) { // Generická funkcia s parametrom typu T
        println(value)
    }
    
  • Vytváranie inštancií generických typov:
    val intBox: Box<Int> = Box(123) // Určenie konkrétneho typu (Int)
    val stringBox = Box("hello") // Kompilátor odvodí typ (String)
    
  • Variabilita: Umožňuje určiť, ako fungujú podtypy s generickými typmi.
    • Kovariencia (out): Umožňuje používanie typu a jeho podtypov. Označuje sa out. Príklad: List<out Any> môže obsahovať List<String>. Používa sa pre typy, ktoré produkujú hodnoty (napríklad čítanie z kolekcie).
      interface Producer<out T> { // out T - kovariantný parameter
           fun produce(): T
      }
      
    • Kontravariancia (in): Umožňuje používanie typu a jeho nadtypov. Označuje sa in. Príklad: Comparator<in String> môže pracovať s Comparator<Any>. Používa sa pre typy, ktoré konzumujú hodnoty (napríklad zápis do kolekcie).
      interface Consumer<in T> { // in T - kontravariantný parameter
          fun consume(value: T)
      }
      
    • Invariancia: Typ v generickom parametri musí byť presne rovnaký. Toto je predvolené správanie.
  • Obmedzenia typov (where): Umožňuje obmedziť typ parametra tak, aby implementoval určité rozhrania alebo dedil z určitej triedy.
    fun <T : Comparable<T>> max(a: T, b: T): T { // T musí implementovať Comparable
        return if (a > b) a else b
    }
    
    fun <T> process(item: T) where T : Runnable, T : Comparable<T> {
        item.run()
        // ... používame porovnateľnosť
    }
    
  • Hviezdička (star) projekcia (*): Používa sa, keď nie sú dôležité konkrétne argumenty typu. Podobne ako <?> v Jave.
    fun printList(list: List<*>) { // Môže prijať zoznam akéhokoľvek typu
         for (item in list) {
             println(item)
         }
    }
    

Generické typy v Kotlinu používajú stratu typov (type erasure), rovnako ako v Jave. Informácie o konkrétnych typoch parametrov sa strácajú počas behu. Na prácu s typmi počas behu sa používajú reified typy.

  • Reified typy (reified): Dostupné sú iba pre inline funkcie. Umožňujú zachovať informácie o type parametra počas behu.
    inline fun <reified T> checkType(value: Any) { // T - reified typ
        if (value is T) {
            println("Value is of type T")
        } else {
            println("Value is not of type T")
        }
    }