PHP týden Body zdarma
Pouze tento týden sleva až 80 % na PHP e-learning
Využij podzimních slev a získej od nás až 40 % bodů zdarma! Více zde

Lekce 6 - Typový systém: Optionals ve Swift

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 ve Swift, jsme se naučili ušetřit si práci pomocí cyklů. Nyní si konečně vysvětlíme koncept tzv. Optionals, který je ve Swift velmi důležitý. Řekneme si, co znamenají všechny ty vykřičníky ve zdrojovém kódu. S několika jsme se už setkali a byť se může pro začátek jednat o složitější koncept, tak bude lepší, když budete alespoň tušit, o co se jedná.

Koncept hodnoty nil

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 Swift 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 nil, která bezpečně označí, že je proměnná prázdná. V ostatních programovacích jazycích se tato hodnota často jmenuje null a funguje úplně stejně.

Pokud si ve Swift vytvoříme standardní proměnnou, prázdnou hodnotu nil do ní přiřadit nelze:

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

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

Optionals

Typ Optional 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ý.

Otazník

Optional 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 = nil

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 = nil
print(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 Swift vynadal i při přístupu k vlastnosti nebo metodě Optional 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"
print(s1.count)
print(s2.count)
Tento výukový obsah pomáhají rozvíjet následující firmy, které dost možná hledají právě tebe!

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

Null safety

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

Vykřičník

Optional můžeme vytvořit ještě druhým způsobem. Pomůže nám s tím vykřičník !:

var vzdyCislo : Int!
// Můžeme napsat print(vzdyCislo + 1), ale aplikace spadne, protože v boxu vzdyCislo ještě číslo není

Tímto způsobem Swiftu říkáme, že se o proměnnou postaráme sami a zajistíme, aby měla před přístupem k ní platnou hodnotu (v tomto případě libovolné celé číslo). V kódu s ní můžeme pracovat jako s obyčejným Int, který jinak bez hodnoty nejde deklarovat, ale snadno nám může program spadnout.

Určitě vám došlo, že význam vykřičníků v kódu je nějaké riziko a měli bychom se jim spíše vyhýbat.

Rozbalujeme box

Nyní si konečně vysvětlíme jak se k hodnotám dostat a proč jsme do našich kódu psali vykřičníky.

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 Swift degradovat na starší jazyky jako je např. Java a kontrolu null safety vypnout. Pokud v proměnné zrovna nebude nil, vše bude fungovat:

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

Výsledek:

30

V anglické terminologii se pro tuto techniku používá výraz force unwrapping (vynutit rozbalení).

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

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

Při překladu bychom na tuto chybu vůbec nepřišli. Tento způsob se využívá velmi zřídka a obecně v případech, kdy víme, že vždy bude hodnota nebo naopak její absence znamená, že nemá smysl kód dále vykonávat, protože jde o něco kritického.

Optional binding

K Optionals bychom měli vždy přistupovat opatrně právě skrze optional binding. Používají se dvě hlavní konstrukce, jedna za pomoci tradiční if podmínky a druhá za pomoci slovíčka guard. Jedná se spíše o sémantické rozdíly (mají jiný význam). Nejdříve si je ukážeme a následně vysvětlíme.

Ošetření Optional hodnoty podmínkou
var optionalNumber : Int? = 5
if let number = optionalNumber {
    print(number * 2)
} else {
    print("Číslo není zadané")
}

Kód v podmínce výše se spustí pouze v případě, že proměnná optionalNumber obsahuje hodnotu. Ta se následně uloží do konstanty number a v těle podmínky s ní pracujeme jako s tradičním Int, takže nejsme dále omezováni.

Pro zajímavost: Můžete používat také if var, ale prakticky se to nedělá, protože je daná proměnná stejně aktivní pouze v tomto bloku a nedává smysl s ní moc manipulovat.

Guard

Stručně se dá říci, že guard funguje opačně a spustí blok v případě, že podmínka neplatí. Používá se pouze ve funkcích, které zatím neumíme, kde z funkce v bloku vystoupí pomocí příkazu return. Ukážeme si jej až dále v kurzu.

Rozbalení pomocí výchozí hodnoty

Ještě si ukážeme další možnost, jak se zbavit Optional a získat tradiční datový typ. Můžeme totiž jednoduše určit náhradní hodnotu, která se použije, pokud je Optional prázdný. Odborně se označuje jako nil coalescing a disponuje vlastním operátorem ??.

var moznaCislo: Int?
moznaCislo = nil

let urciteCislo = moznaCislo ?? 4

print(urciteCislo)

Můžete vidět, že operátor ?? je binární, tudíž vyžaduje hodnoty na obou stranách. Pokud levá strana není nil (respektive prázdný Optional), tak operátor dále nic neřeší a přiřadí tuto hodnotu. Jestli je ale nil, tak dojde k přiřazení druhé hodnoty.

Zde se nám vypíše 4, protože je proměnná moznaCislo nil. Toto se hodí v případě, že lze rozumně pokračovat také s výchozí hodnotou, kterou přes ?? nastavíme. Tento operátor je možné řetězit, ale pro přehlednost bych to nedoporučoval.

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


 

 

Článek pro vás napsal Filip Němeček
Avatar
Jak se ti líbí článek?
2 hlasů
Autor se věnuje vývoji iOS aplikací (občas macOS) či těch webových ve frameworku Django. Twitter: @nemecek_f | GitHub nemecek-filip
Předchozí článek
Cykly ve Swift
Všechny články v sekci
Základní konstrukce jazyka Swift
Miniatura
Následující článek
Pole ve Swift
Aktivity (9)

 

 

Komentáře

Avatar
Michal Martinec:17. ledna 16:05

Z tohto som debil

Odpovědět 17. ledna 16:05
Neporovnavaj sa s ostatnymi. Porovnavaj sa sam so sebou.
Avatar
Filip Němeček
Redaktor
Avatar
Odpovídá na Michal Martinec
Filip Němeček:17. ledna 18:15

Koncept Optionals je pro začátek celkem náročný na pochopení, už v začátcích je ale potřeba a proto je zařazen jako jeden z prvních tutoriálů.

Zkus si to třeba za den dva přečíst znovu, nebo se ptej, co nebude jasné ;-)

 
Odpovědět 17. ledna 18:15
Avatar
Odpovídá na Filip Němeček
Michal Martinec:17. ledna 19:18

Ahoj, ja som sa to aj opýtal konrétne, ale na telefóne a za debil som dal smajlika a vsetko ostatne komentár ignoroval, chyba v kóde :D Tak este raz. Nechápem, preco do Int? vlozim najprv 15 a potom mu dam hodnotu nil. Pride mi to zbytocne. Nemozem rovno premennej dat hodnotu nil? Musim jej dat najprv nejakú hodnotu a az potom jej dat hodnotu nil? Je mozne, ze nasavam tie informacie prilis rychlo a nieco sa mi pomiesalo v hlave preco tomu nerozumiem.

Odpovědět 17. ledna 19:18
Neporovnavaj sa s ostatnymi. Porovnavaj sa sam so sebou.
Avatar
Filip Němeček
Redaktor
Avatar
Odpovídá na Michal Martinec
Filip Němeček:17. ledna 20:21

Jasně že můžeš :-) Tady v tom tutoriálu je spousta příkladů ukázána tak, jak nebudou fungovat, aby bylo možné ukázat třeba problém při použití "!" na rozbalení Optional.

 
Odpovědět 17. ledna 20:21
Tento výukový obsah pomáhají rozvíjet následující firmy, které dost možná hledají právě tebe!
Avatar
Michal Martinec:17. ledna 20:31

Takze aby sme si rozumeli. Nemusím písať var moznaCislo: Int? = 15
moznaCislo = nil

ale mozem rovno

var moznaCislo: Int? = nil

Tym padom som usetril riadok a logicky to bude fungovat. Tym padom je vychodiskova hodnota moznaCislo nil a ked nahodou sa do nej prida ciselna hodnota tak sa prepise na tu ciselnu hodnotu. v opacnom pripade ostane nil ano?

Odpovědět 17. ledna 20:31
Neporovnavaj sa s ostatnymi. Porovnavaj sa sam so sebou.
Avatar
Odpovídá na Filip Němeček
Michal Martinec:17. ledna 20:32

Prepac za duplicitu ale nedal som odpovedat :)

Takze aby sme si rozumeli. Nemusím písať var moznaCislo: Int? = 15
moznaCislo = nil

ale mozem rovno

var moznaCislo: Int? = nil

Tym padom som usetril riadok a logicky to bude fungovat. Tym padom je vychodiskova hodnota moznaCislo nil a ked nahodou sa do nej prida ciselna hodnota tak sa prepise na tu ciselnu hodnotu. v opacnom pripade ostane nil ano?

Odpovědět 17. ledna 20:32
Neporovnavaj sa s ostatnymi. Porovnavaj sa sam so sebou.
Avatar
Filip Němeček
Redaktor
Avatar
Odpovídá na Michal Martinec
Filip Němeček:18. ledna 9:21

Ano, vlastně stačí pouze:
var moznaCislo: Int?

Aby proměnná byla nil, jelikož to je u Optional výchozí hodnota.

 
Odpovědět  +1 18. ledna 9:21
Avatar
Odpovídá na Filip Němeček
Michal Martinec:18. ledna 9:22

Dakujem krasne za odpovede a vysvetlenie. :)

Odpovědět 18. ledna 9:22
Neporovnavaj sa s ostatnymi. Porovnavaj sa sam so sebou.
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 8 zpráv z 8.