Vydělávej až 160.000 Kč měsíčně! Akreditované rekvalifikační kurzy s garancí práce od 0 Kč. Více informací.
Hledáme nové posily do ITnetwork týmu. Podívej se na volné pozice a přidej se do nejagilnější firmy na trhu - Více informací.

Lekce 13 - Dynamic, var, null a null aware operátory

V předešlém cvičení, Řešené úlohy k 11.-12. lekci Dartu, jsme si procvičili nabyté zkušenosti z předchozích lekcí.

V minulé lekci kurzu, Řešené úlohy k 11.-12. lekci Dartu, jsme se naučili pracovat s matematikou. V této lekci se zaměříme na datový typ dynamic a hodnotu null. O té jsme se již v rámci kurzu nejednou zmiňovali a dnes si ukážeme jak s ní pracovat.

Datový typ dynamic

Datový typ dynamic se hodí v situacích, kdy nevíte datový typ proměnné, nebo ho nechcete určovat. V proměnné tak může být naprosto cokoli a kdykoli se může měnit i její datový typ. V jedné chvíli tak v proměnné alfa může být celé číslo a poté do ní přiřadíme řetězec:

dynamic alfa = 5;
print(alfa);
alfa = 'aaa';
print(alfa);

S takovou proměnnou se nám ale velmi špatně pracuje, jelikož nevíme my ani IDE, co v ní právě je uloženo. Tím pádem nám IDE neumí napovídat. Pokud to není nezbytně nutné nebo vhodné, dynamic bychom používat neměli a raději bychom jej měli nahradit za konkrétní datový typ.

var

Zmíníme ještě jedno klíčové slovo, kterým je var. Psát datové typy je občas zbytečné, např. v momentě, kdy víme, jaký datový typ dosazujeme, protože jsme ho např. definovali už někde výše. Představme si, že máme např. 2 proměnné, kde obě mají nějaký velmi složitý datový typ:

List<List<List<List<List<List<int>>>>>> a = [];
List<List<List<List<List<List<int>>>>>> b = a;

Psát takovéto typy 2x není zas až takový problém. Psát je už ale stále dokola je zbytečné a hlavně nepřehledné. Proto v momentě, kdy je kód dostatečně přehledný i pochopitelný bez opakování datového typu, můžeme využít klíčové slovo var, které nám, jednoduše řečeno, dosadí ten správný typ a zpřehlední tím kód.

List<List<List<List<List<List<int>>>>>> a = [];
var b = a;

Stejně tak můžeme klíčové slovo var použít kdekoli, kde dosazujeme literál.

var a = 1; // int
var b = 1.0; // double
var c = 'ahoj'; // String

Pozor však na situace, kdy bychom chtěli mít např. seznam prvků s libovolným datovým typem. Literál by ovšem obsahoval jen jeden datový typ, což var vyhodnotí jako seznam jen tohoto jednoho datové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 prvním případě, pokud bychom se pokusili přidat řetězec do seznamu, nám vyhubuje i statická analýza kódu, která vypíše chybu "error: The argument type 'String' can't be assigned to the parameter type 'int'. (argument_type_not_as­signable at [muj_projekt] bin\muj_projek­t.dart:8)".

Všimněte si, že datový typ prvků seznamu můžeme vynutit napsáním typu do špičatých závorek < > před literál.

Užívejte tedy var pouze v případech, pokud kód neztratí na přehlednosti a pokud jste si jisti, že se vyhodnotí správně. Var by se nám neměl plést s dynamic, var za nás pouze typ sám napíše, ale neumožňuje jej měnit a proměnná se chová stejně, jako bychom typ napsali ručně.

Hodnota null

Několikrát jsme si zmínili hodnotu null a sliboval jsem, že si ji dovysvětlíme. Cokoli v Dartu, co vytvoříme, ale nic do toho nepřiřadíme, má výchozí hodnotu null. Hodnotu null můžeme chápat jako "nic"; dokonce až takové "nic", že na ní nemůžeme volat téměř žádné metody nebo vlastnosti a pokud to uděláme, program se většinou ukončí s chybou.

Pozn.: Na null můžeme ve skutečnosti volat pouze metody, které má Object. Nám prozatím postačí vědět, že je to například metoda toString(). Tento fakt ale nic nemění na okolnostech, že náš program může spadnout, což rozhodně nechceme.

Že se nám program opravdu ukončí s chybou si ukážeme na příkladu výpisu absolutní hodnoty čísla:

int cislo; // obsahuje null
print(cislo.abs());

Výstup programu:

Konzolová aplikace
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)

Již z minula víme, že hodnota null se dá využít i na dobré věci (např. detekci, že jsme nenačetli opravdu nic, místo toho, abychom hodnotu nastavili např. na 0), ale nyní jsme také zjistili, že je null potenciálně nebezpečný a musíme s ním zacházet opatrně.

Nejjednodušší ochranou, kterou byste již měli být schopni sami zvládnout, jsou podmínky:

int cislo; // obsahuje null

if (cislo != null) {
    print(cislo.abs());
} else {
    print('Číslo neexistuje.');
}

Výstup programu:

Konzolová aplikace
Číslo neexistuje.

Asi ale sami tušíte, že psát podmínku vždy, když si nejsme jistí, že proměnná je nebo není null není moc hezké. A není to ani zrovna dvakrát přehledné přehledné. Naštěstí jsou v Dartu tzv. null-aware operátory, které nám s tím hodně pomohou.

Null-aware operátory

Operátor ??

Operátor ?? použijeme všude tam, kde chceme vrátit hodnotu výrazu a v případně, že byl výraz null, pak vrátit jeho alternativu.

int cislo; // obsahuje null
print(cislo ?? 'Nic.');
cislo = 5;
print(cislo ?? 'Nic.');

Výstup programu:

Konzolová aplikace
Nic.
5

Operátor ??=

Operátor ??= použijeme všude tam, kde chceme přiřadit alternativní hodnotu, pokud je původní hodnota proměnné null. Výsledek po použití operátoru je samozřejmě buď původní hodnota, pokud nebyla null, nebo alternativa.

int cislo; // obsahuje null
print(cislo ??= 42);
print(cislo);

int druheCislo; // obsahuje null
druheCislo ??= 666;
print(druheCislo);

Výstup programu:

Konzolová aplikace
42
42
666

Operátor ?.

Operátor ?. použijeme všude tam, kde chceme volat metodu a nejsme si jisti, jestli není výraz null. Pokud je null, nic se neprovede a výraz vrací hodnota null.

Ukážeme si náš původní příklad s absolutní hodnotou:

int cislo; // obsahuje null
print(cislo?.abs());

Výstup programu:

Konzolová aplikace
null

Pokud bychom chtěli volat více metod za sebou, třeba zjistit, jestli je absolutní hodnota sudá, použijeme operátor ?. v celém výrazu vícekrá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á aplikace
null
true
false

Jednotlivé operátory můžeme samozřejmě kombinovat:

int cislo; // obsahuje null
print(cislo?.abs() ?? 'Číslo neexistuje.');

Výstup programu:

Konzolová aplikace
Číslo neexistuje.

Už jsme skoro u konce. Příští lekce, Ekosystém a konvence Dartu, je vlastně bonusová a nebude se týkat kódu, ale ekosystému Dart programů a konvencím v Dartu.


 

Předchozí článek
Řešené úlohy k 11.-12. lekci Dartu
Všechny články v sekci
Základní konstrukce jazyka Dart
Přeskočit článek
(nedoporučujeme)
Ekosystém a konvence Dartu
Článek pro vás napsal Honza Bittner
Avatar
Uživatelské hodnocení:
3 hlasů
FIT ČVUT alumnus :-) Sleduj mě na https://twitter.com/tenhobi a ptej se na cokoli na https://github.com/tenhobi/ama.
Aktivity