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.