NOVINKA - Online rekvalifikační kurz Java programátor. Oblíbená a studenty ověřená rekvalifikace - nyní i online.
NOVINKA – Víkendový online kurz Software tester, který tě posune dál. Zjisti, jak na to!

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:

let muz = true // nějaká proměnná udávající pohlaví
let nazevPohlavi: String
if muz {
    nazevPohlavi = "muž"
} else {
    nazevPohlavi = "žena"
}

print(nazevPohlavi)

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:

let muz = true
let nazevPohlavi = muz ? "muž" : "žena"
print(nazevPohlavi)

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

let pohlavi = "nevim"
let nazevPohlavi = pohlavi == "muz" ? "muž" : pohlavi == "zena" ? "žena" : "nezname"
print(nazevPohlavi)

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ě:

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í")
}

Jak ale použít switch pro takovýto příklad? Možná by vás napadl následující zápis:

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
}

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:

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
}

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":

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ů.")

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.


 

Předchozí článek
Vícerozměrná pole ve Swift
Všechny články v sekci
Základní konstrukce jazyka Swift
Přeskočit článek
(nedoporučujeme)
Cykly ve Swift podruhé - repeat...while, break a continue
Článek pro vás napsal Filip Němeček
Avatar
Uživatelské hodnocení:
7 hlasů
Autor se věnuje vývoji iOS aplikací (občas macOS)
Aktivity