Akce! Dobij si body, napiš nám do zpráv "Přes léto se to naučím!" a dobijeme ti ještě navíc 50% z této částky! Sleva na výuku platí do 22.6.2018.

Lekce 6 - Typový systém: Null safety v Kotlin

Kotlin Základy Typový systém: Null safety v Kotlin

ONEbit hosting Unicorn College Tento obsah je dostupný zdarma v rámci projektu IT lidem. Vydávání, hosting a aktualizace umožňují jeho sponzoři.

V minulé lekci, Cykly v Kotlin, jsme se naučili ušetřit si práci pomocí cyklů. Nyní si konečně vysvětlíme koncept tzv. null safety, který je v Kotlin velmi důležitý a řekneme si, co znamenají všechny ty vykřičníky ve zdrojovém kódu. S několika jsme se již setkali a byť se může pro začátek jednat o složitější koncept, tak bude lepší, když budeme alespoň tušit, o co se jedná.

Koncept hodnoty null

Programovací jazyky se musí nějak vypořádat se situací, kdy proměnná nemá žádnou hodnotu. S takovým problémem se často setkáváme u funkcí, které se nemusí provést korektně. Pokud se např. nepodaří načtení čísla z konzole, nemělo by být vráceno žádné číslo, ale "prázdno". Pokud by nám Kotlin vrátil v tomto případě např. hodnotu 0 nebo -1, nepoznali bychom zda se číslo nepodařilo načíst nebo zda uživatel vložil právě 0 nebo -1. Za tímto účelem se vymyslela speciální hodnota null, která bezpečně označí, že je proměnná prázdná.

Pokud si v Kotlin vytvoříme standardní proměnnou, prázdnou hodnotu null do ní přiřadit nelze:

// Tento kód je chybný
var cislo = 15
cislo = null // Tento řádek vyvolá chybu

Někdo by ji tam totiž nemusel očekávat. Abychom null mohli do proměnné přiřadit, musíme proměnnou deklarovat jako nullovatelnou.

Nullovatelné typy

Nullovatelný typ můžeme chápat jako jakýsi box, který slouží k zabalení obyčejné proměnné. Box vždy existuje, po jeho otevření ale hodnotu buď najdeme nebo je prázdný. Nullable typ vytvoříme tak, že za název datového typu proměnné umístíme otazník ?. Zkusme si to:

var moznaCislo: Int? = 15
moznaCislo = null

Kód se již přeložil v pořádku a proměnná moznaCislo je nyní prázdná, i když se jedná o číslo. To zní zatím dobře, že?

Je tu ovšem problém, který mnoho ostatních programovacích jazyků nedokáže vyřešit. S moznaCislo by nám nyní nemělo být umožněno pracovat jako s obyčejnou proměnnou. Pokud bychom napsali:

var moznaCislo: Int? = 15
moznaCislo = null
println(moznaCislo  * 2)

a program se přeložil, mohl by za běhu spadnout v případě, že by moznaCislo bylo prázdné. Nemůžeme přeci vynásobit "nezadáno" dvěma. Když si takový program zkusíte napsat, zjistíte, že nejde přeložit. Podobně by nám Kotlin vynadal i při přístupu k vlastnosti nebo metodě nullovatelného typu. Můžete si zkusit, že kvůli výpisu délky druhého řetězce nepůjde následující kód přeložit:

var s1 = "Ahoj"
var s2: String? = "Světe"
println(s1.length)
println(s2.length)

Asi jste tušili, že Kotlin nepatří mezi jazyky, které by si tento problém neohlídaly :)

Null safety

Mechanismus, který již při překladu kontroluje jak nullovatelné typy používáme, se nazývá null safety. Existuje několik způsobů jak nullovatelnou proměnnou použít. Postupně si je vyzkoušíme.

Operátor !!

Začněme tím nejhloupějším, který jsme zatím v kurzu používali, aby toho na nás nebylo ze začátku moc. Pomocí operátoru !! můžeme Kotlin degradovat na starší jazyky jako je např. Java a kontrolu null safety vypnout. Pokud v proměnné zrovna nebude null, vše bude fungovat:

var moznaCislo: Int? = 15
println(moznaCislo!!  * 2)

Výsledek:

30

Pokud v ní ovšem prázdná hodnota bude, celá aplikace za běhu upadne s chybou.

var moznaCislo: Int? = 15
moznaCislo = null
println(moznaCislo!!  * 2)

Jelikož při překladu bychom na tuto chybu vůbec nepřišli, nebudeme odteď řešení s !! vůbec používat.

Podmínka

O něco chytřejší řešení je pracovat s nullovatelnými typy v podmínce na hodnotu null. Jelikož se tak vyhneme pádu programu, Kotlin nám program dovolí přeložit:

var moznaCislo: Int? = 15
if (moznaCislo != null)
        println(moznaCislo  * 2)
else
        println("Číslo není zadané!")

Bezpečné volání

Určitě tušíte, že existuje lepší řešení než psát stále podmínky na null. Pomocí operátoru ?. (otazník tečka) se buď přistoupí k dané vlastnosti nebo se vrátí null v případě, že je proměnná prázdná.

?.let

Pokud bychom použili bezpečné volání spolu s klíčovým slovem let, spustil by se kód ve složených závorkách pouze v případě, že by v proměnné byla ne-nullová hodnota:

var moznaCislo: Int? = 15
moznaCislo?.let { println(it) }

Klíčové slovo it následně v bloku obsahuje tuto hodnotu. Pokud by bylo moznaCislo null, program by se přeložil a výpis by se nespustil.

Řetězení ?.

Tuto funkcionalitu využijeme pouze v případě, když se chceme zeptat přes řetěz vlastností jako např.:

zak?.ucitel?.nadrizeny?.jmeno

Výraz výše vrátí buď název ředitele školy (nadřízeného učitele žáka) nebo null v případě, že je jakýkoli článek výrazu prázdný. Ušetříme tak spoustu podmínek, ovšem musíme pamatovat na to, že ve výsledku máme stále ač jeden tak stále nullovatelný typ.

Mohli bychom takto i bezpečně přiřadit, již bez potřeby dalších podmínek:

zak?.ucitel?.nadrizeny?.jmeno = "Seymour Skinner"

Elvis operátor

Elvis operátor v Kotlin

Jak vznikl název tohoto operátoru asi netřeba vysvětlovat :) Elvise používáme spolu s operátorem ?. a umožňuje nám zeptat se, zda je hodnota v nullovatelné proměnné null a případně použít jinou výchozí hodnotu. Opět si to zkusme na našem příkladu:

var moznaText: String? = "Ahoj světe"
println(moznaText?.length ?:  0)

Na pravé straně elvis operátoru můžeme použít i return nebo vyvolání výjimek (viz další kurzy).

V každém ze způsobů práce s hodnotou null platí, že pokud je hodnota null, další výrazy (metody) určené pro případ kdyby null nebyla se nespustí.

V příští lekci, Pole v Kotlin, se budeme věnovat polím.


 

 

Článek pro vás napsal Samuel Kodytek
Avatar
Jak se ti líbí článek?
1 hlasů
Autor se věnuje Javě, Kotlinu, PHP, C, HTML. Zajímá ho spíše game design.
Miniatura
Předchozí článek
Cykly v Kotlin
Miniatura
Všechny články v sekci
Základní konstrukce jazyka Kotlin
Miniatura
Následující článek
Pole v Kotlin
Aktivity (3)

 

 

Komentáře

Avatar
neutr
Člen
Avatar
neutr:21. dubna 10:43

Velmi pěkné - jenom mi nějak nedochází proč, nebo k čemu je výraz "it" (z výrazu moznaCislo?.let { println(it) }). Pokud je to v závorce tak ta tam není jenom pro "it". Já bych tam čekal spíš třeba "this", ale nemám na mysli význam jako synonymum - zde by "it" bylo kratší a tím pádem lepší.

Připadá mi, že by mělo existovat více výrazů které lze do závorky použít a nepůjde o jeden účel. Zatím to vypadá jako ukazatel. Asi by stačila jen poznámečka. Díky

 
Odpovědět 21. dubna 10:43
Avatar
gcx11
Redaktor
Avatar
Odpovídá na neutr
gcx11:21. dubna 19:48

Zde se it používá jako implicitní název parametru, který se do té funkce vloží.

Pokud by neexistoval implicitní název parametru, tak by se muselo psát něco takového, stejně jako v C# u lambda funkcí:

moznaCislo?.let { i -> println(i) }

A podobných funkcí existuje v Kotlinu více, například tato, která se chová podobně, ale bere jako parametr this:

moznaCislo?.run { println(this) }
 
Odpovědět  +2 21. dubna 19:48
Děláme co je v našich silách, aby byly zdejší diskuze co nejkvalitnější. Proto do nich také mohou přispívat pouze registrovaní členové. Pro zapojení do diskuze se přihlas. Pokud ještě nemáš účet, zaregistruj se, je to zdarma.

Zobrazeno 2 zpráv z 2.