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í.

6. diel - Typový systém: Optionals vo Swift

V predchádzajúcom cvičení, Riešené úlohy k 5. lekcii Swift, sme si precvičili získané skúsenosti z predchádzajúcich lekcií.

V minulej lekcii, Riešené úlohy k 5. lekcii Swift , sme sa naučili ušetriť si prácu pomocou cyklov. Teraz si konečne vysvetlíme koncept tzv. Optionals, ktorý je vo Swift veľmi dôležitý. Povieme si, čo znamenajú všetky tie výkričníky v zdrojovom kóde. S niekoľkými sme sa už stretli a hoci sa môže pre začiatok jednať o zložitejší koncept, tak bude lepšie, keď budete aspoň tušiť, o čo sa jedná.

Koncept hodnoty nil

Programovacie jazyky sa musí nejako vysporiadať so situáciou, kedy premenná nemá žiadnu hodnotu. S takýmto problémom sa často stretávame u funkcií, ktoré sa nemusia vykonať korektne. Ak sa napr. Nepodarí načítanie čísla z konzoly, nemalo by byť vrátený žiadne číslo, ale "prázdno". Ak by nám Swift vrátil v tomto prípade napr. Hodnotu 0 alebo -1, nepoznali by sme či sa číslo nepodarilo načítať alebo či používateľ vložil práve 0 alebo -1. Za týmto účelom sa vymyslela špeciálnu hodnota nil, ktorá bezpečne označí, že je premenná prázdna. V ostatných programovacích jazykoch sa táto hodnota často volá null a funguje úplne rovnako.

Ak si vo Swift vytvoríme štandardnej premennú, prázdnu hodnotu nil do nej priradiť nedá:

// Tento kód je nesprávny
var cislo = 15
cislo = nil // Tento riadok vyvolá chybu

Niekto by ju tam totiž nemusel očakávať. Aby sme nil mohli do premennej priradiť, musíme premennú označil ako Optional.

Optionals

Typ Optional môžeme chápať ako akýsi box, ktorý slúži na zabalenie obyčajné premenné. Box vždy existuje, po jeho otvorení ale hodnotu buď nájdeme, alebo je prázdny.

Otáznik

Optional typ vytvoríme tak, že za názov dátového typu premennej umiestnime otáznik ?. Skúsme si to:

var moznaCislo: Int? = 15
moznaCislo = nil

Kód sa už preložil v poriadku a premenná moznaCislo je teraz prázdna, aj keď sa jedná o číslo. To znie zatiaľ dobre, že?

Je tu však problém, ktorý mnoho ostatných programovacích jazykov nedokáže vyriešiť. S moznaCislo by nám teraz nemalo byť umožnené pracovať ako s obyčajnou premennou. Ak by sme napísali:

var moznaCislo: Int? = 15
moznaCislo = nil
print(moznaCislo  * 2)

a program sa preložil, mohol by za behu spadnúť v prípade, že by moznaCislo bolo prázdne. Nemôžeme predsa vynásobiť "nezadané" dvoma. Keď si taký program skúsite napísať, zistíte, že nejde preložiť. Podobne by nám Swift vynadal aj pri prístupe k vlastnosti alebo metóde Optional typu. Môžete si skúsiť, že kvôli výpisu dĺžky druhého reťazca nepôjde nasledujúci kód preložiť:

var s1 = "Ahoj"
var s2: String? = "Svete"
print(s1.count)
print(s2.count)

Asi ste tušili, že Swift nepatrí medzi jazyky, ktoré by si tento problém neohlídaly :)

Null safety

Mechanizmus, ktorý už pri preklade kontroluje ako Optional typy používame, sa často nazýva null safety. Existuje niekoľko spôsobov ako Optional premennú použiť. Postupne si ich vyskúšame.

Výkričník

Optional môžeme vytvoriť ešte druhým spôsobom. Pomôže nám s tým výkričník !:

var vzdyCislo : Int!
// Môžeme napísať print (vzdyCislo + 1), ale aplikácia spadne, pretože v boxe vzdyCislo ešte číslo nie je

Týmto spôsobom Swiftu hovoríme, že sa o premennú postaráme sami a zaistíme, aby mala pred prístupom k nej platnú hodnotu (v tomto prípade ľubovoľné celé číslo). V kóde s ňou môžeme pracovať ako s obyčajným Int, ktorý inak bez hodnoty nejde deklarovať, ale ľahko nám môže program spadnúť.

Určite vám došlo, že význam výkričníkov v kóde je nejaké riziko a mali by sme sa im skôr vyhýbať.

Rozbaľujeme box

Teraz si konečne vysvetlíme ako sa k hodnotám dostať a prečo sme do našich kódu písali výkričníky.

Operátor !

Začnime tým najhlúpejšom, ktorý sme zatiaľ v kurze používali, aby toho na nás nebolo zo začiatku moc. Pomocou operátora ! môžeme Swift degradovať na staršie jazyky ako je napr. Java a kontrolu null safety vypnúť. Ak v premennej zrovna nebude nil, všetko bude fungovať:

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

výsledok:

30

V anglickej terminológii sa pre túto techniku používa výraz force unwrapping (vynútiť rozbalenia).

Pokiaľ v premennej však prázdna hodnota bude, celá aplikácia za behu upadne s chybou.

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

Pri preklade by sme na túto chybu vôbec neprišli. Tento spôsob sa využíva veľmi zriedka a všeobecne v prípadoch, keď vieme, že vždy bude hodnota alebo naopak jej absencia znamená, že nemá zmysel kód ďalej vykonávať, keďže ide o niečo kritického.

Optional binding

K Optionals by sme mali vždy pristupovať opatrne práve skrze optional binding. Používajú sa dve hlavné konštrukcie, jedna za pomoci tradičné if podmienky a druhá za pomoci slovíčka guard. Ide skôr o sémantickej rozdiely (majú iný význam). Najskôr si ich ukážeme a následne vysvetlíme.

Ošetrenie Optional hodnoty podmienkou
var optionalNumber : Int? = 5
if let number = optionalNumber {
    print(number * 2)
} else {
    print("Číslo nie je zadané")
}

Kód v podmienke vyššie sa spustí len v prípade, že premenná optionalNumber obsahuje hodnotu. Tá sa následne uloží do konštanty number a v tele podmienky s ňou pracujeme ako s tradičným Int, takže nie sme ďalej obmedzovaní.

Pre zaujímavosť: Môžete používať tiež if var, ale prakticky sa to nerobí, pretože je daná premenná rovnako aktívny len v bloku a nedáva zmysel s ňou moc manipulovať.

guard

Stručne sa dá povedať, že guard funguje opačne a spustí blok v prípade, že podmienka neplatí. Používa sa iba vo funkciách, ktoré zatiaľ nevieme, kde z funkcie v bloku vystúpi pomocou príkazu return. Ukážeme si ho až ďalej v kurze.

Rozbalení pomocou predvolené hodnoty

Ešte si ukážeme ďalšiu možnosť, ako sa zbaviť Optional a získať tradičné dátový typ. Môžeme totiž jednoducho určiť náhradnú hodnotu, ktorá sa použije, ak je Optional prázdny. Odborne sa označuje ako nil coalescing a disponuje vlastným operátorom ??.

var moznaCislo: Int?
moznaCislo = nil

let urciteCislo = moznaCislo ?? 4

print(urciteCislo)

Môžete vidieť, že operátor ?? je binárny, teda vyžaduje hodnoty na oboch stranách. Ak ľavá strana nie je nil (respektíve prázdny Optional), tak operátor ďalej nič nerieši a priradí túto hodnotu. Ak je ale nil, tak dôjde k priradenie druhej hodnoty.

Tu sa nám vypíše 4, pretože je premenná moznaCislo nil. Toto sa hodí v prípade, že sa dá rozumne pokračovať aj s východiskovou hodnotou, ktorú cez ?? nastavíme. Tento operátor je možné reťaziť, ale pre prehľadnosť by som to nedoporučoval.

V budúcej lekcii, Poľa vo Swift , sa budeme venovať poliam.


 

Predchádzajúci článok
Riešené úlohy k 5. lekcii Swift
Všetky články v sekcii
Základné konštrukcie jazyka Swift
Preskočiť článok
(neodporúčame)
Poľa vo Swift
Článok pre vás napísal Filip Němeček
Avatar
Užívateľské hodnotenie:
Ešte nikto nehodnotil, buď prvý!
Autor se věnuje vývoji iOS aplikací (občas macOS)
Aktivity