IT rekvalifikace s garancí práce. Seniorní programátoři vydělávají až 160 000 Kč/měsíc a rekvalifikace je prvním krokem. Zjisti, jak na to!
Hledáme nové posily do ITnetwork týmu. Podívej se na volné pozice a přidej se do nejagilnější firmy na trhu - Více informací.

1. diel - Úvod do kolekcií a genericita v Kotlin

Vitajte v online kurze zameranom na rôzne typy kolekcií programovacieho jazyka Kotlin a na genericitu.

Kolekcia

Pojem kolekcia označuje súbor dát, ktoré sú väčšinou rovnakého typu a slúžia na špecifický účel. Počas Kotlin kurzu sme sa už stretli s dvoma typmi kolekciou, bolo to pole a okrajovo List. Kolekcií existuje veľké množstvo a hoci sa zvonku mnohokrát tvária podobne, vo vnútri fungujú veľmi odlišne a vyberáme si ich podľa konkrétneho účelu.

Generické a všeobecné kolekcie

Keď sa zamyslíme nad tým, ako by sme si urobili vlastnú kolekciu, určite by sme po nejakej dobe dospeli k problému. Bol by ním dátový typ kolekcie. Chceli by sme si napr. Naprogramovať vlastný List, vytvorili by sme triedu MujList.kt, do nej pridali príslušnej metódy a všetko potrebné. Pretože však chceme, aby bola naša kolekcia univerzálne a vedela teda ukladať napr. Ako Int y, tak užívateľov, bude problém s dátovým typom prvkov vnútri kolekcie. Tento problém vyrieši tzv. Generické kolekcie, ktoré sa líšia od tých všeobecných.

Všeobecné kolekcia

Keďže vieme, že všetky dátové typy majú ako predka triedu Any, mohli by sme prvky v našej kolekcii ukladať práve do tohto dátového typu. Do kolekcie teraz môžeme uložiť v podstate čokoľvek. Nevýhodou je, že sama kolekcia skutočný dátový typ prvkov nepozná a preto vie prvky navracať len ako všeobecné objekty. Po získaní prvku z kolekcie si ho teda musíme pretypovať.

Uveďme si príklad, ako by taká všeobecná kolekcia mohla vyzerať v Kotlinu, keby sme si snažili skomplikovať život. Použijeme na to typ Array<Any>:

val array = arrayOf("položka", 123, 30.0)

val polozka: String = array[0] as String

Tým, že vytvoríme Array s rôznymi objektmi (String, Int a Double), sa nám vytvorí Array<Any>. Aby sme tieto položky mohli z poľa následne získať späť, je potrebné ich na String spätne pretypovať.

Generické kolekcia

Generické kolekcia rieši problém s dátovým typom na úrovni jazyka Kotlin. Zavádza tzv. Genericitu. Zjednodušene povedané sa jedná o možnosť špecifikovať typ údajov až vo chvíli vytvorenie inštancie. V triede samotnej kolekcie sa potom pracuje s generickým typom, ktorý slúži ako zástupca pre budúce dátový typ. Môžeme si to predstaviť tak, že sa generický typ v triede zmení napr. Na String vo chvíli, keď vytvoríme jej inštanciu. Jedná sa teda o možnosť triedy nejakým spôsobom parametrizovať.

Generický Array už poznáme a onen dátový typ (parameter) sa generickým triedam špecifikuje vo špicatých zátvorkách. Dátový typ môžeme špecifikovať iba raz, pri vytvorení kolekcie. Akékoľvek ďalšie pretypovanie odpadá a pri čítaní získame vždy objekt daného typu:

val array: Array <String> = arrayOf("položka", "položka_2", "položka_3")

val polozka: String = array[0]

Generické kolekcia v ostatných programovacích jazykoch postupne vytlačili kolekcie všeobecné. V Kotlinu, ako čisto modernom jazyku, všeobecné kolekcie už ani neexistujú, ak si nevynutíme cez generík typ Any.

Genericita

Genericita je samozrejme vlastnosť jazyka Kotlin a my ju máme možnosť vo svojich triedach používať.

Zatiaľ sa nebudeme zaťažovať tvorbou vlastnej kolekcie. Vytvorme si triedu, ktorá bude jednoducho spravovať jednu premennú. Premenná bude generická, teda ľubovoľného dátového typu. Založte si nový projekt, konzolovú aplikáciu s názvom Genericita. Pridajte si novú triedu, pomenujte ju teraz pre študijné účely iba Trida. V jej deklarácii pridáme generický parameter, ktorý pomenujeme T:

class Trida<T> {
}

Generických parametrov môžeme zadať vo špicatých zátvorkách viac, oddelíme ich čiarkou. Niekedy sa to môže hodiť, my sa s tým stretneme ďalej u generických slovníkov.

Presunieme sa do funkcie main(), kde si vytvoríme inštanciu našej triedy:

val t = Trida<Int>()

Nezabudneme na špicaté zátvorky buď u dátového typu, alebo u konstruktoru. Teraz sme parametra T v tejto inštanciu triedy určili dátový typ Int. Rovnako tak si môžeme urobiť ďalší inštanciu tej istej triedy a parametra T dať úplne iný dátový typ, napr. String. Stačí nám teda 1 trieda pre viac dátových typov.

Pokračujme a vytvorme si v triede atribút. T môžeme použiť ako bežný dátový typ:

class Trida<T>(private val promenna: T) {
}

V main() aktualizujeme vytvorení inštancie:

val t = Trida<Int>(10)

Kotlín je dostatočne šikovný, aby sme mohli deklaráciu typu aj vynechať, odvodí si ju sám z typu parametra:

val t = Trida(10) //Typu Trida<Int>

Teraz inštancie obsahuje atribút promenna, ktorý je typu Int a nadobúda hodnoty 10.

Môžeme dokonca pridať metódu, ktorá bude mať naviac ďalšie generický parameter (iný, než má trieda). Mohla by vyzerať napr. Nasledovne:

fun<T2> porovnej(a: T2): Boolean = (a == promenna)

Skúsime si teda porovnať náš Int s nejakým iným typom:

t.porovnej<String>("15")

Alebo môžeme zavolať:

t.porovnej("15")

Kotlín obsahuje ešte mocnejší konštrukcie ako je napríklad slovíčko out a in u definície generík, ale na úvod do generík mi to prišlo príliš komplikované. Je to skôr pre pokročilejšie publikum a znalca Javy.

Ďalšie konštrukcie

Pre úplnosť si ešte uveďme niekoľko konštrukcií.

Generický parameter triedy je možné bližšie špecifikovať, presnejšie obmedziť. Slúži na to kľúčový operátor :. Môžeme tak nastaviť, že udaný dátový typ musí napr. Obsahovať rozhranie Comparable<*> (k hviezdičke sa dostanem nižšie):

class Trida<T: Comparable<*>>(private val promenna: T) {
    //...
}

Vďaka tomu môžeme na premenných typu T teraz vnútri triedy volať metódy z daného rozhrania, abstraktné triedy alebo poděděné triedy. Samotné rozhranie môže opäť obsahovať generický parameter (tu to tak je), aby sme generické typy mohli používať aj v hlavičkách jeho metód.

* Tu slúži ako taký wild card (žolík), chceme akúkoľvek triedu čo implementuje Comparable, ale je nám jedno aký typ porovnáva. Keby sme chceli iba triedu čo porovnáva Int y, použili by sme:

class Trida<T: Comparable<Int>>(private val promenna: T) {
    //...
}

Nakoniec si ukážme, ako môžeme typ parametra obmedziť z hľadiska dedičnosti.

class Trida<A: B, B: C, C> {
}

Vyššie sme deklarovali triedu s tromi generickými parametrami, kde A je potomkom B a B je potomkom C.

V budúcej lekcii, Zoznam (List) pomocou poľa v Kotlin , na nás čakajú zoznamy.


 

Mal si s čímkoľvek problém? Stiahni si vzorovú aplikáciu nižšie a porovnaj ju so svojím projektom, chybu tak ľahko nájdeš.

Stiahnuť

Stiahnutím nasledujúceho súboru súhlasíš s licenčnými podmienkami

Stiahnuté 19x (13.41 kB)
Aplikácia je vrátane zdrojových kódov v jazyku Kotlin

 

Všetky články v sekcii
Kolekcia v Kotlin
Preskočiť článok
(neodporúčame)
Zoznam (List) pomocou poľa v Kotlin
Článok pre vás napísal Samuel Kodytek
Avatar
Užívateľské hodnotenie:
Ešte nikto nehodnotil, buď prvý!
Autor se věnuje všem jazykům okolo JVM. Rád pomáhá lidem, kteří se zajímají o programování. Věří, že všichni mají šanci se naučit programovat, jen je potřeba prorazit tu bariéru, který se říká lenost.
Aktivity