Lekce 12 - Podmínky ve Swift podruhé - Ternární výraz a mocnější switch
V minulé lekci, Vícerozměrná pole ve Swift, jsme si představili vícerozměrná pole.
V dnešním Swift tutoriálu si představíme 2 další konstrukce, které souvisejí s podmínkami. Jedná se o oddechovou lekci, kterou toto téma dokončíme.
Ternární operátor
Často se nám stává, že někde potřebujeme nastavit 2 různé hodnoty podle toho, zda platí nějaká podmínka.
Příklad - Výpis pohlaví
Představme si, že máme např. pohlaví uživatele uložené jako
Bool
(muž by byl true
) a my bychom ho chtěli
převést do textu. S dosavadními znalostmi bychom napsali asi takovýto
kód:
{SWIFT}
let muz = true // nějaká proměnná udávající pohlaví
let nazevPohlavi: String
if muz {
nazevPohlavi = "muž"
} else {
nazevPohlavi = "žena"
}
print(nazevPohlavi)
{/SWIFT}
Výstup programu je samozřejmě následující:
muž
Kód je poměrně upovídaný na to, že jen přepíná mezi dvěma hodnotami. Proto programovací jazyky často podporují tzv. ternární výraz.
Syntaxe ternárního výrazu
Pomocí tohoto operátoru můžeme získat hodnotu podle platnosti logického výrazu. Zapíšeme jej takto:
výraz ? hodnota1 : hodnota2
Podmínku vložíme většinou do závorky ()
, pokud je
složitější, poté následuje otazník ?
a dvě hodnoty, které
se mají vrátit. Hodnoty jsou oddělené dvojtečkou :
, první se
vrátí když podmínka platí a druhá když neplatí. Jak snadné! Název operátoru je odvozený od
toho, že má 3 části (podmínka, první hodnota a druhá hodnota), proto
ternární.
Příklad - Použití ternárního výrazu
Pojďme si ternární operátor vyzkoušet na příkladu s pohlavím:
{SWIFT}
let muz = true
let nazevPohlavi = muz ? "muž" : "žena"
print(nazevPohlavi)
{/SWIFT}
Místo typu Bool
bychom mohli samozřejmě napsat
jakoukoli jinou podmínku, např.
(vek >= 18) ? "zletilý" : "nezletilý"
.
Vnořování ternárních operátorů
Ternární operátory lze teoreticky zanořovat do sebe a tím reagovat i na tři a více hodnot. Nicméně ve většině případů zanořování spíše kód znepřehlední, vznikají totiž dlouhé nebo podivně zalomené řádky a není na první pohled vidět, jaká část se kdy spustí. Ukažme si, jak by se pomocí vnořování ternárních výrazů vyřešil výpis tří pohlaví:
{SWIFT}
let pohlavi = "nevim"
let nazevPohlavi = pohlavi == "muz" ? "muž" : pohlavi == "zena" ? "žena" : "nezname"
print(nazevPohlavi)
{/SWIFT}
Pro příklad výše by bylo lepší vytvořit vlastní metodu, což si ale ukážeme až v navazujícím kurzu objektově orientovaného programování.
Pokročilejší switch
S konstrukcí switch
jsme se již setkali v lekci Podmínky (větvení). Dnes
si ukážeme její další použití, které není tak časté, ale můžete na
něj narazit. Jakmile switch
vykoná první case
, tak
se jeho provádění ukončí. Můžeme ale použít speciální klíčové
slovo fallthrough
a toto chování upravit.
V jazycích jako C dokonce
switch
automaticky "propadává", takže je nutné psát
explicitně break
do každé větve.
Příklad - Čtvrtletí
Předpokládejme, že chceme podle měsíce v roce zjistit, jaké je
čtvrtletí. Pomocí if
a else
by příklad vypadal
následovně:
{SWIFT}
let mesic = 2
if mesic >= 1 && mesic <= 3 {
print("Je první čtvrtletí")
} else if mesic >= 4 && mesic <= 6 {
print("Je druhé čtvrtletí")
} else if mesic >= 7 && mesic <= 9 {
print("Je třetí čtvrtletí")
} else if mesic >= 10 && mesic <= 12 {
print("Je čtvrté čtvrtletí")
}
{/SWIFT}
Jak ale použít switch
pro takovýto příklad? Možná by vás
napadl následující zápis:
{SWIFT}
let mesic = 11
switch mesic {
case 1:
print("Je první čtvrtletí")
case 2:
print("Je první čtvrtletí")
case 3:
print("Je první čtvrtletí")
case 4:
print("Je druhé čtvrtletí")
case 5:
print("Je druhé čtvrtletí")
case 6:
print("Je druhé čtvrtletí")
case 7:
print("Je třetí čtvrtletí")
case 8:
print("Je třetí čtvrtletí")
case 9:
print("Je třetí čtvrtletí")
case 10:
print("Je čtvrté čtvrtletí")
case 11:
print("Je čtvrté čtvrtletí")
case 12:
print("Je čtvrté čtvrtletí")
default:
break
}
{/SWIFT}
Příklad funguje spolehlivě, problém však je, že jsme si tímto zápisem moc nepomohli. Podobnému repetitivnímu kódu bychom se vždy měli vyhýbat.
Definice více hodnot a rozsahu
case
Jednotlivé case
ve Swiftu mohou být definované pro více
hodnot. Například case 1, 2, 3
, který se provede, pokud bude
mít proměnná jednu z těchto hodnot.
Ještě lepší je potom možnost využít typ Range
a použít
tento zápis: case 1...3
. Mohli bychom zapsat také jako
case 1..<4
.
Upravme náš příklad:
{SWIFT}
let mesic = 11
switch mesic {
case 1, 2, 3:
print("Je první čtvrtletí")
case 4...6:
print("Je druhé čtvrtletí")
case 7...9:
print("Je třetí čtvrtletí")
case 10...12:
print("Je čtvrté čtvrtletí")
default:
break
}
{/SWIFT}
Ukázka výstupu aplikace:
Je čtvrté čtvrtletí.
Tento zápis je již mnohem přehlednější. A pro podobné případy se dost dobře hodí.
Kdybyste něčeho podobného chtěli docílit s if
, tak je
nutné použít metodu contains()
na instanci Range
.
Vypadalo by to nějak takto:
if (1...3).contains(mesic) { print("Je první čtvrtletí") }
Switch a propadávání
Propadávání ve switch
pomocí klíčového slova
fallthrough
je poměrně kuriózní záležitost a dá práci
vymyslet příklad, kde by mělo alespoň smysl. Jednoduše provedení jednoho
case
s fallthrough
uvnitř způsobí, že program pak
propadne i všemi dalšími case
, aniž by
kontroloval jejich podmínku. Ačkoli to v praxi asi
nepoužijeme, jedná se o gramatiku Swift a můžete na ni narazit v cizích
kódech.
Ukažme si jeden takový příklad, i když by šel napsat jednodušeji bez
propadávání. Pokud chcete kód vyzkoušet u sebe, tak v Xcode musíte
vytvořit Command Line Tool, v Playground totiž readLine()
nefunguje. Nebo si prostě do konstanty vstup
uložte něco jako
"1gb"
:
{SWIFT}
let vstup = readLine()!.trimmingCharacters(in: .whitespacesAndNewlines).lowercased().replacingOccurrences(of: "b", with: "")
let jednotka: Character = vstup.last!
var hodnota = Double(String(vstup.dropLast()))!
switch(jednotka)
{
case "y":
hodnota *= 1024
fallthrough
case "z":
hodnota *= 1024
fallthrough
case "e":
hodnota *= 1024
fallthrough
case "p":
hodnota *= 1024
fallthrough
case "t":
hodnota *= 1024
fallthrough
case "g":
hodnota *= 1024
fallthrough
case "m":
hodnota *= 1024
fallthrough
case "k":
hodnota *= 1024
default:
break
}
print("Soubor má \(hodnota) bajtů.")
{/SWIFT}
Výstup:
1gb Soubor má 1073741824.0 bajtů.
Program převádí velikost souboru zadanou např. v megabajtech nebo
gigabajtech na bajty. Jak vidíme, jednotky následují postupně za sebou a
jakmile najdeme case
, který odpovídá zadané jednotce,
pronásobí se zadaná hodnota i v těch následujících case
. To
proto, že např. 1
GB má 1024
MB a ten má také
1024
KB a ten má 1024
bajtů, násobíme
1024
tedy hned 3x. Mnohem lepší by ovšem bylo uložit si
jednotky do pole a to procházet cyklem, než programovat takto repetitivně to
samé násobení znovu a znovu.
Jak už jsme si řekli, ve Swiftu nedochází k automatickému propadávání
u case
, takže do nich nemusíme psát break
.
Propadnutí ale můžeme vynutit pomocí klíčového slova
fallthrough
. To způsobí, že program "propadne" na všechny
další case
, který také vykoná, zde už je jedno, jestli je
splněná podmínka. Zatím jsem se s fallthrough
osobně nepotkal,
můžete se hodit např., když byste chtěli vykonat default
blok,
případě u pokročilejších konstrukcí, kde v rámci jednoho
case
zachytáváte více podmínek.
V příští lekci, Cykly ve Swift podruhé - repeat...while, break a continue, na nás čeká další syntaxe okolo cyklů, na kterou můžeme narazit v cizích zdrojových kódech.