Lekce 3 - Typový systém podruhé: Datové typy ve Swift
V předešlém cvičení, Řešené úlohy k 1.-2. lekci Swift, jsme si procvičili nabyté zkušenosti z předchozích lekcí.
Nyní se na datové typy podíváme více zblízka a vysvětlíme si, kdy jaký použít. Dnešní lekce bude hodně teoretická, ale o to více bude praktická ta příští. Na konci si vytvoříme pár jednoduchých ukázek.
Swift rozeznává dva druhy datových typů, hodnotové a referenční. Těm referenčním se budeme věnovat později.
Hodnotové datové typy
Proměnné hodnotového datového typu si dokážeme jednoduše představit. Může se jednat např. o číslo nebo znak. V paměti je jednoduše uložena přímo hodnota a my k této hodnotě můžeme z programu přímo přistupovat. Slovo přímo jsem tolikrát nepoužil jen náhodou. V tomto Swift kurzu se budeme věnovat výhradně těmto proměnným.
Celočíselné datové typy
Podívejme se nyní na tabulku všech vestavěných celočíselných
datových typů ve Swift, všimněte si typu Int
, který již
známe z minula.
Datový typ | Rozsah | Velikost |
---|---|---|
Int | -2 147 483 648 až 2 147 483 647 | 32 bitů |
UInt | 0 až 4 294 967 295 | 32 bitů |
Rozsahy těchto typů si samozřejmě nemusíte pamatovat, pro celá čísla
můžete jednoduše používat vždy typ Int
.
Více informací můžete nalézt v oficiální dokumentaci. Tu otevřete
skrze Help -> Developer Documentation. Pak už stačí jen vyhledávat. Ke
konkrétním datovým typům apod. se můžete snadno dostat skrze Quick Help
inspektor v pravé straně Xcode. Stačí mít označený např.
Int
typ a v inspektoru kliknout na Structure Reference.
Prefix U
u UInt
znamená, že neumožňuje uložit
zápornou hodnotu a tím pádem může uložit dvojnásobnou kladnou. Těmto
typům se říká unsigned, klasickým
signed.
Desetinná čísla
U desetinných čísel je situace podobná, máme na výběr dva datové
typy. Samozřejmě se liší opět v rozsahu hodnoty, dále však ještě v
přesnosti (vlastně počtu des. míst). Typ Double
má již dle
názvu dvojnásobnou přesnost oproti Float
.
Datový typ | Rozsah | Přesnost |
---|---|---|
Float | +-1.5 * 10−45 až +-3.4 * 1038 | 7 čísel |
Double | +-5.0 * 10−324 až +-1.7 * 10308 | 15-16 čísel |
Vzhledem k tomu, že desetinná čísla jsou v počítači uložena ve dvojkové soustavě, dochází k určité ztrátě přesnosti. Odchylka je sice téměř zanedbatelná, nicméně když budete programovat např. finanční systém, nepoužívejte tyto dat. typy pro uchování peněz, mohlo by dojít k malým odchylkám.
Typ Double
je pro desetinná čísla výchozí,
Float
je tak nutné blíže specifikovat.
let f : Float = 3.14 let d = 2.72
Jako desetinný separátor používáme ve zdrojovém kódu vždy tečku, nehledě na to, jaké máme v macOS regionální nastavení.
Další vestavěné datové typy
Podívejme se na další datové typy, které nám Swift nabízí:
Datový typ | Rozsah | Velikost/Přesnost |
---|---|---|
Character | U+0000 až U+ffff | 16 bitů |
Decimal | +-1.0 * 10−28 až +-7.9 * 1028 | 28-29 čísel |
Bool | true nebo false | 8 bitů |
Character
Character nám reprezentuje jeden znak, na rozdíl od String
,
který reprezentoval celý řetězec hodnot typu Character
. Znaky v
Swift píšeme do klasických uvozovek a datový typ je nutné specifikovat,
jinak bude použit String
:
let c : Character = "A"
Decimal
Typ Decimal
řeší problém ukládání desetinných čísel v
binární podobě, ukládá totiž číslo vnitřně podobně jako text.
Používá se tedy pro uchování peněžních hodnot. Ke všem dalším
matematickým operacím s des. čísly použijeme Double
nebo
Float
. K zápisu Decimal
hodnoty opět musíme datový
typ specifikovat:
let number : Decimal = 3.14159265358979323846
Bool
Datový typ Bool
nabývá dvou hodnot: true
(pravda) a false
(nepravda). Budeme ho používat zejména tehdy,
až se dostaneme k podmínkám. Do proměnné typu Bool
lze uložit
jak přímo hodnotu true
/false
, tak i logický výraz.
Zkusme si jednoduchý příklad:
{SWIFT}
let b = false
let vyraz = 15 > 5
print(b)
print(vyraz)
{/SWIFT}
Výstup programu:
false true
Výrazy můžeme psát do závorek. To se hodí v případě, že jich máme
např. několik. Vidíme, že výraz nabývá hodnoty true
(pravda), protože 15
je opravdu větší než 5
. Od
výrazů je to jen krok k podmínkám, na ně se podíváme příště.
String
Datový typ, se kterým se setkáte na každém kroku. Reprezentuje řetězec znaků, či prostě jakýkoliv text. Jedná se o hodnotový typ. My si ukážeme hlavně důležité metody, které je dobré znát nebo alespoň vědět, že existují. Metody zkoušejte v Command Line, ne v Playground.
contains()
,
hasSuffix()
a hasPreffix()
Můžeme se jednoduše zeptat, zda řetězec začíná, končí nebo zda
obsahuje určitý podřetězec (substring). Podřetězcem myslíme část
původního řetězce. Všechny tyto metody budou jako parametr brát
samozřejmě podřetězec a vracet hodnoty typu Bool
(true
/false
). Zatím na výstup neumíme reagovat, ale
pojďme si ho alespoň vypsat:
{SWIFT}
let s = "Krokonosohroch"
print(s.hasPrefix("krok"))
print(s.hasSuffix("hroch"))
print(s.contains("nos"))
print(s.contains("roh"))
{/SWIFT}
Výstup programu:
false true true false
Vidíme, že vše funguje podle očekávání. První výraz samozřejmě neprošel díky tomu, že řetězec ve skutečnosti začíná velkým písmenem.
uppercased()
a
lowercased()
Rozlišování velkých a malých písmen může být někdy na obtíž.
Mnohdy se budeme potřebovat zeptat na přítomnost podřetězce tak, aby
nezáleželo na velikosti písmen. Situaci můžeme vyřešit pomocí metod
uppercased()
a lowercased()
, které vrací řetězec
ve velkých a v malých písmenech. Uveďme si reálnější příklad než je
Krokonosohroch. Budeme mít v proměnné řádek konfiguračního souboru,
který psal uživatel. Jelikož se na vstupy od uživatelů nelze spolehnout,
musíme se snažit eliminovat možné chyby, zde např. s velkými písmeny.
{SWIFT}
var konfig = "Fullscreen shaDows autosave"
konfig = konfig.lowercased()
print("Poběží hra ve fullscreenu?")
print(konfig.contains("fullscreen"))
print("Budou zapnuté stíny?")
print(konfig.contains("shadows"))
print("Přeje si hráč vypnout zvuk?")
print(konfig.contains("nosound"))
print("Přeje si hráč hru automaticky ukládat?")
print(konfig.contains("autosave"))
{/SWIFT}
Výstup programu:
Poběží hra ve fullscreenu? true Budou zapnuté stíny? true Přeje si hráč vypnout zvuk? false Přeje si hráč hru automaticky ukládat? true
Vidíme, že jsme schopni zjistit přítomnost jednotlivých slov v řetězci tak, že si nejprve řetězec převedeme celý na malá písmena (nebo na velká) a potom kontrolujeme přítomnost slova jen malými (nebo velkými) písmeny. Takhle by mimochodem mohlo opravdu vypadat jednoduché zpracování nějakého konfiguračního skriptu.
trimmingCharacters()
Problémem ve vstupech od uživatele může být i diakritika. Swift ale
naštěstí pracuje plně v Unicode, nestane se nám tedy, že by se diakritika
nějak zkomolila. Další nástrahou mohou být mezery a obecně všechny tzv.
bílé znaky, které nejsou vidět, ale mohou nám uškodit. Obecně může být
dobré tzv. trimovat všechny vstupy od uživatele. Máme dostupnou metodu
trimmingCharacters(in: )
, přičemž je ještě nutné zadat, co
budeme trimovat, protože se jedná o výčet, tak napíšeme .
a
Xcode nám samo navrhne hromadu možností, co trimmovat. Nejčastěji budete
používat možnost .whitespacesAndNewlines
, což odstraní
všechny bílé znaky a také odřádkování okolo řetězce.
{SWIFT}
print("Zadejte číslo:")
let s = readLine()!
print("Zadal jste text: " + s)
print("Text po funkci trim: " + s.trimmingCharacters(in: .whitespacesAndNewlines))
let a = Int(s)!
print("Převedl jsem zadaný text na číslo parsováním, zadal jste: \(a)")
{/SWIFT}
replacingOccurrences()
Asi nejdůležitější metodou na String
je nahrazení určité
jeho části jiným textem. Jako parametry zadáme dva podřetězce, jeden co
chceme nahrazovat a druhý ten, kterým to chceme nahradit. Metoda vrátí nový
String
, ve kterém proběhlo nahrazení. Když daný podřetězec
metoda nenajde, vrátí původní řetězec. Zkusme si to:
{SWIFT}
let s = "Java je nejlepší!"
let replaced = s.replacingOccurrences(of: "Java", with: "Swift")
print(replaced)
{/SWIFT}
Výstup programu:
Swift je nejlepší!
Iterpolace řetězců
Interpolaci řetězců jsme si již zmiňovali. Ve Swift argumenty či
jednoduše proměnné, které chceme do řetězce na určitá místa vložit,
zapíšeme přímo do stringu pomocí \()
:
{SWIFT}
let a = 10
let b = 20
let c = a + b
let s = "Když sečteme \(a) a \(b), dostaneme \(c)"
print(s)
{SWIFT}
Výstup programu:
Když sečteme 10 a 20, dostaneme 30
Funkce print()
sama umí přijímat text v takovémto formátu,
můžeme tedy napsat:
let a = 10 let b = 20 let c = a + b print("Když sečteme \(a) a \(b), dostaneme \(c)")
Toto je velmi užitečná a přehledná cesta, jak sestavovat řetězce.
Pokud chceme vypsat čísla, tak se ji nevyhnete. U více Stringů můžete
použít konkatenaci (jednoduše +
pro jejich "sečtení").
Vlastnost count
Poslední, ale nejdůležitější vlastnost (pozor, ne metoda) je
count
, tedy počet znaků. Vrací celé číslo, které
představuje počet znaků v řetězci. Za vlastnosti nepíšeme závorky,
protože nemají parametry. Slovo "length" by dávalo intuitivně větší
smysl, ale Swift vlastnost bere jako zmiňovaný počet znaků, takže si holt
musíme zvyknout na count
.
{SWIFT}
print("Zadejte vaše jméno:")
let jmeno = readLine()!
print("Délka vašeho jména je: \(jmeno.count)")
{/SWIFT}
Padding
Padding znamená, že Stringu přidáme znaky, abychom ho dostali na požadovanou délku. Často se používá pro přidání mezer, ale můžete doplnit jakýkoliv znak. Některé jazyky nabízí pohodlné metody pro padding zleva nebo zprava. Swift má pouze jednu a chce po nás celkem dost parametrů. Podrobně si ji popíšeme dále v kurzu.
Pokud vám nějaké metody z této lekce nefungují,
ujistěte se, že máte v souboru import Foundation
pro
importování základní Swift funkcionality.
Je toho ještě spoustu k vysvětlování a jsou další datové typy, které jsme neprobrali.
V následujícím cvičení, Řešené úlohy k 3. lekci Swift, si procvičíme nabyté zkušenosti z předchozích lekcí.