13. diel - Dynamic, var, null a null aware operátormi
V predchádzajúcom cvičení, Riešené úlohy k 11.-12. lekciu Dart, sme si precvičili získané skúsenosti z predchádzajúcich lekcií.
V minulej lekcii kurzu, Riešené úlohy k 11.-12. lekciu Dart , sme sa naučili pracovať s matematikou.
V tejto lekcii sa zameriame na dátový typ dynamic
a hodnotu
null
. O tej sme sa už v rámci kurzu neraz zmieňovali a dnes si
ukážeme ako s ňou pracovať.
Dátový typ dynamic
Dátový typ dynamic
sa hodí v situáciách, keď neviete
dátový typ premennej, alebo ho nechcete určovať. V premennej tak môže byť
úplne čokoľvek a kedykoľvek sa môže meniť aj jej dátový typ. V jednej
chvíli tak v premennej alfa
môže byť celé číslo a potom do
nej priradíme reťazec:
dynamic alfa = 5; print(alfa); alfa = 'aaa'; print(alfa);
S takou premennú sa nám ale veľmi zle pracuje, pretože nevieme my ani
IDE, čo v nej práve je uložené. Tým pádom nám IDE nevie napovedať. Ak to
nie je nevyhnutné alebo vhodné, dynamic
by sme používať nemali
a radšej by sme ho mali nahradiť za konkrétny typ údajov.
Var
Spomenieme ešte jedno kľúčové slovo, ktorým je var
.
Písať dátové typy je občas zbytočné, napr. V momente, keď vieme, aký
typ údajov dosadzujeme, pretože sme ho napr. Definovali už niekde vyššie.
Predstavme si, že máme napr. 2 premenné, kde obe majú nejaký veľmi
zložitý dátový typ:
List<List<List<List<List<List<int>>>>>> a = []; List<List<List<List<List<List<int>>>>>> b = a;
Písať takéto typy 2x nie je zas až taký problém. Písať je už ale
stále dokola je zbytočné a hlavne neprehľadné. Preto v momente, kedy je
kód dostatočne prehľadný aj pochopiteľný bez opakovania dátového typu,
môžeme využiť kľúčové slovo var
, ktoré nám, jednoducho
povedané, dosadí ten správny typ a sprehľadní tým kód.
List<List<List<List<List<List<int>>>>>> a = []; var b = a;
Rovnako tak môžeme kľúčové slovo var použiť kdekoľvek, kde dosadzujeme literál.
var a = 1; // int var b = 1.0; // double var c = 'ahoj'; // String
Pozor však na situácie, kedy by sme chceli mať napr. Zoznam prvkov s
ľubovoľným dátovým typom. Literál by však obsahoval len jeden typ
údajov, čo var
vyhodnotí ako zoznam len tohto jedného
dátového typu:
var a = [1, 2, 3, 4, 5]; // List<int> // a.add('alfa'); ... chyba var b = [1, 2, 3, 4, 5, 'alfa']; // List<dynamic> b.add('beta'); var c = <dynamic>[1, 2, 3, 4, 5]; // List<dynamic> c.add('alfa');
V prvom prípade, ak by sme sa pokúsili pridať reťazec do zoznamu, nám vynadá aj statická analýza kódu, ktorá vypíše chybu "error: The argument type 'String' can not be assigned to the parameter type 'int'. (Argument_type_not_assignable at [muj_projekt ] bin \ muj_projekt.dart: ".
Všimnite si, že dátový typ prvkov zoznamu môžeme vynútiť napísaním
typu do špicatých zátvoriek < >
pred literál.
Užívajte teda var
iba v prípadoch, ak kód nestratí na
prehľadnosti a ak ste si istí, že sa vyhodnotí správne. Var by sa nám
nemal pliesť s dynamic
, var
za nás len typ sám
napíše, ale neumožňuje ho meniť a premenná sa správa rovnako, ako by sme
typ napísali ručne.
Hodnota null
Niekoľkokrát sme si spomenuli hodnotu null
a sľuboval som,
že si ju dovysvětlíme. Čokoľvek v Dart, čo vytvoríme, ale nič do toho
nepriradíte, má predvolenú hodnotu null
. Hodnotu
null
môžeme chápať ako "nič"; dokonca až také "nič", že na
nej nemôžeme volať takmer žiadne metódy alebo vlastnosti a ak to urobíme,
program sa väčšinou ukončí s chybou.
Pozn .: Na null
môžeme v skutočnosti volať iba metódy,
ktoré má Object
. Nám zatiaľ postačí vedieť, že je to
napríklad metóda toString()
. Tento fakt ale nič nemení na
okolnostiach, že náš program môže spadnúť, čo rozhodne
nechceme.
Že sa nám program naozaj ukončí s chybou si ukážeme na príklade výpise absolútnej hodnoty čísla:
int cislo; // obsahuje null print(cislo.abs());
Výstup programu:
Konzolová aplikácia
Unhandled exception:
NoSuchMethodError: The method 'abs' was called on null.
Receiver: null
Tried calling: abs()
#0 Object._noSuchMethod (dart:core-patch/object_patch.dart:43)
#1 Object.noSuchMethod (dart:core-patch/object_patch.dart:47)
#2 main (file:///D:/git/muj_projekt/bin/muj_projekt.dart:5:15)
#3 _startIsolate.<anonymous closure> (dart:isolate-patch/isolate_patch.dart:265)
#4 _RawReceivePortImpl._handleMessage (dart:isolate-patch/isolate_patch.dart:151)
Už z minula vieme, že hodnota null
sa dá využiť aj na
dobré veci (napr. Detekciu, že sme neprevzali naozaj nič, namiesto toho, aby
sme hodnotu nastavili napr. Na 0
), ale teraz sme tiež zistili, že
je null
potenciálne nebezpečný a musíme s ním zaobchádzať
opatrne.
Najjednoduchšie ochranou, ktorú by ste už mali byť schopní sami zvládnuť, sú podmienky:
int cislo; // obsahuje null if (cislo != null) { print(cislo.abs()); } else { print('Číslo neexistuje.'); }
Výstup programu:
Konzolová aplikácia
Číslo neexistuje.
Asi ale sami tušíte, že písať podmienku vždy, keď si nie sme istí,
že premenná je alebo nie je null
nie je moc pekné. A nie je to
ani práve dvakrát prehľadné prehľadné. Našťastie sú v Dart tzv.
Null-aware operátory, ktoré nám s tým veľa pomôžu.
Null-aware operátory
Operátor ??
Operátor ??
použijeme všade tam, kde chceme vrátiť hodnotu
výrazu a v prípadne, že bol výraz null
, potom vrátiť jeho
alternatívu.
int cislo; // obsahuje null print(cislo ?? 'Nic.'); cislo = 5; print(cislo ?? 'Nic.');
Výstup programu:
Konzolová aplikácia
Nic.
5
Operátor ?? =
Operátor ??=
použijeme všade tam, kde chceme priradiť
alternatívne hodnotu, ak je pôvodná hodnota premennej null
.
Výsledok po použití operátora je samozrejme buď pôvodná hodnota, pokiaľ
nebola null
, alebo alternatíva.
int cislo; // obsahuje null print(cislo ??= 42); print(cislo); int druheCislo; // obsahuje null druheCislo ??= 666; print(druheCislo);
Výstup programu:
Konzolová aplikácia
42
42
666
Operátor?.
Operátor ?.
použijeme všade tam, kde chceme volať metódu a
nie sme si istí, či nie je výraz null
. Ak je null
,
nič sa nevykoná a výraz vracia hodnota null
.
Ukážeme si náš pôvodný príklad s absolútnou hodnotou:
int cislo; // obsahuje null print(cislo?.abs());
Výstup programu:
Konzolová aplikácia
null
Ak by sme chceli volať viac metód za sebou, treba zistiť, či je
absolútna hodnota párna, použijeme operátor ?.
v celom výrazu
viackrát.
int cislo; // obsahuje null print(cislo?.abs()?.isEven); cislo = -8; print(cislo?.abs()?.isEven); cislo = 7; print(cislo?.abs()?.isEven);
Výstup programu:
Konzolová aplikácia
null
true
false
Jednotlivé operátormi môžeme samozrejme kombinovať:
int cislo; // obsahuje null print(cislo?.abs() ?? 'Číslo neexistuje.');
Výstup programu:
Konzolová aplikácia
Číslo neexistuje.
Už sme skoro u konca. Budúci lekcie, Ekosystém a konvencie Dart , je vlastne bonusová a nebude sa týkať kódu, ale ekosystému Dart programov a konvenciám v Dart.