7. diel - Ošetrenie užívateľských vstupov v Dart
V predchádzajúcom cvičení, Riešené úlohy k 6. lekcii Dart, sme si precvičili získané skúsenosti z predchádzajúcich lekcií.
V minulej lekcii, Riešené úlohy k 6. lekcii Dart , sme sa zaoberali cykly. Dnes to bude také oddychové, dokončíme si totiž našu kalkulačku, ďalej už ju nebudeme potrebovať a bolo by pekné ju dotiahnuť do konca. Asi tušíte, že u nej chýba zabezpečenia vstupov od užívateľa, tým sa bude zaoberať dnešný tutoriál.
Pripomeňme si kód našej kalkulačky:
print('Vítejte v kalkulačce'); String pokracovat = 'ano'; while (pokracovat == 'ano') { print('Vítejte v kalkulačce'); print('Zadejte první číslo:'); double a = double.parse(stdin.readLineSync(encoding: UTF8)); print('Zadejte druhé číslo:'); double b = double.parse(stdin.readLineSync(encoding: UTF8)); print('Zvolte si operaci:'); print('1 - sčítání'); print('2 - odčítání'); print('3 - násobení'); print('4 - dělení'); int volba = int.parse(stdin.readLineSync(encoding: UTF8)); double vysledek; switch (volba) { case 1: vysledek = a + b; break; case 2: vysledek = a - b; break; case 3: vysledek = a * b; break; case 4: vysledek = a / b; break; } if ((volba > 0) && (volba < 5)) print('Výsledek: $vysledek'); else print('Neplatná volba'); print('Přejete si zadat další příklad? [ano/ne]'); pokracovat = stdin.readLineSync(encoding: UTF8); } print('Děkuji za použití kalkulačky.');
Už sme si raz hovorili, že by sme mali vstupy od užívateľa vždy ošetrovať. Poviem vám tajomstvo úspešných a obľúbených aplikácií, je veľmi jednoduché: počítajú s tým, že je používateľ úplný hlupák.:) Čím hlúpejšieho užívateľa budete predpokladať, tým väčší úspech budú vaše aplikácie mať. Pokiaľ tu používateľ zadá miesto "áno" napr. "Áno" (áno medzera) alebo "Áno" (s veľkým písmenom), program rovnako skončí. To ešte nemusí byť kvôli hlúposti, ale preto, že sa preklepli. Môže nám však zadať aj niečo úplne nezmyselného, napr. "Možno".
To nie je však najväčší problém nášho programu, keď používateľ nezadá číslo, ale nejaký nezmysel, celý program sa zastaví a spadne s chybou. Poďme teraz tieto dva problémy opraviť.
Na overenie správnosti vstupu pri jeho parsovanie môžeme použiť metódu
parse()
s prídavným parametrom onError
. Parameter
onError
očakáva metódu, ktorá nejakým spôsobom spracuje
neplatný reťazec a vráti výslednú hodnotu.
print('Zadejte první číslo:'); double a; while ((a = double.parse(stdin.readLineSync(encoding: UTF8), (_) => null)) == null) print('Neplatné číslo, zadejte prosím znovu:');
Na kódu nie je nič zložité. Najprv vyzveme užívateľa na zadanie
čísla a deklarujeme premennú a
. Následne priamo do podmienky
while
cyklu vložíme parse()
, výsledok uložíme do
premennej aa hodnotu porovnáme voči hodnote null
(o tom, čo je
null
a ako s hodnotou pracovať si povieme neskôr, zatiaľ ju
berme ako prázdnu hodnotu). Kým podmienka bude platiť, bude sa cyklus stále
opakovať a vyzývať k novému zadaniu.
Teraz sa ešte pozrieme na výber operácie a pokračovanie. Obe voľby
načítame ako String
aj keď to nie je úplne vhodné. U čísel
to má opodstatnenie, pretože môžu mať dĺžku väčšie ako jeden znak a
musí byť odenterovány. U voľby operácií 1-4 ale vôbec nepotrebujeme
načítavať text, stačí načítať jediný znak z klávesnice. Dart nemá
načítanie z konzoly vyriešené najlepšie a okrem načítanie celé riadky
(stdin.readLineSync()
) poskytuje ešte metódu
stdin.readByteSync()
na načítanie jediného znaku
(konkrétnejšie asi bytu). Keďže nám vráti len hondnotu znaku, musíme ho
ešte napríklad pomocou ASCII dekodéra previesť na znak, kedy je v tomto
riešení problém napr. S diakritikou. Otázka u tejto metódy ale tiež je,
ako sa presne bude správať na rôznych operačných systémoch a či nám
vždy naozaj načíta celý znak. Metódu si vyskúšame, ale ďalej budeme
načítavať celý riadok a hodnoty si parsovať ako doteraz.
String volba = ASCII.decode([stdin.readByteSync()]); bool platnaVolba = true; double vysledek; switch (volba) { case '1': vysledek = a + b; break; case '2': vysledek = a - b; break; case '3': vysledek = a * b; break; case '4': vysledek = a / b; break; default: platnaVolba = false; } if (platnaVolba) print('Výsledek: $vysledek'); else print('Neplatná volba');
Do premennej volba
si uložíme stlačený znak ako
String
. Pretože rozsah znakov neotestujete s doterajšími
znalosťami tak jednoducho ako rozsah čísiel, pomôžeme si iným spôsobom.
Pripravíme si premennú platnaVolba
typu bool
, ktorú
nastavíme na true
(budeme predpokladať, že je voľba správna).
Switch zostane podobný, len čísla dáme teraz do apostrofov či úvodzoviek.
Pridáme možnosť default
, ktorá v prípade iné hodnoty než
menované nastaví nami pripravenú premennú platnaVolba
na
false
. Potom nie je nič jednoduchšie, než túto premennú
otestovať. Vyskúšajte si to. Určite si všimnete ďalšie "chyby" pri
používaní stdin.readByteSync()
a to síce toho, že prečíta
náš znak, ale nechá nám na vstupe odriadkovanie, čo následne dotaz na
opakovanie kalkulačky zle vyhodnotí a program nám ukončí.
Program si teda upravíme do pôvodnej podoby. Upraviť musíme ešte výzvu
na pokračovanie. Zadávať budeme opäť A / N, budeme tolerovať rôznu
veľkosť písmen a reagovať na zlé zadanie. Opäť použijeme
switch
, našu premennú pokracovat
zmeníme na typ
bool
. Kód je asi zbytočné viac popisovať, za zmienku stojí iba
kombo stdin.readLineSync(encoding: UTF8).trim().toLowerCase()
,
ktoré načíta vstup z konzoly a vráti ho ako String
malými
písmenami a bez počiatočných či ukončovacích medzier.
Pretože sa jedná o väčší kus kódu, použijeme tzv. Komentáre. Tie sa píšu pomocou dvojlomítka (dvoch lomítok za sebou). Sú to informácie pre programátora, program si ich nevšíma.
print('Vítejte v kalkulačce'); bool pokracovat = true; while (pokracovat) { // načtení čísel print('Zadejte první číslo:'); double a; while ((a = double.parse(stdin.readLineSync(encoding: UTF8), (_) => null)) == null) print('Neplatné číslo, zadejte prosím znovu:'); print('Zadejte druhé číslo:'); double b; while ((b = double.parse(stdin.readLineSync(encoding: UTF8), (_) => null)) == null) print('Neplatné číslo, zadejte prosím znovu:'); // volba operace a výpočet print('Zvolte si operaci:'); print('1 - sčítání'); print('2 - odčítání'); print('3 - násobení'); print('4 - dělení'); int volba = int.parse(stdin.readLineSync(encoding: UTF8)); double vysledek = 0.0; bool platnaVolba = true; switch (volba) { case 1: vysledek = a + b; break; case 2: vysledek = a - b; break; case 3: vysledek = a * b; break; case 4: vysledek = a / b; break; default: platnaVolba = false; } if (platnaVolba) print('Výsledek: $vysledek'); else print('Neplatná volba'); print('Přejete si zadat další příklad? [a/n]'); // dotaz na pokračování platnaVolba = false; while (!platnaVolba) { switch (stdin.readLineSync(encoding: UTF8).trim().toLowerCase()) { case 'a': pokracovat = true; platnaVolba = true; break; case 'n': pokracovat = false; platnaVolba = true; break; default: print('Neplatná volba, zadejte prosím a/n'); break; } } } print('Děkuji za použití kalkulačky.');
Výstup programu:
Konzolová aplikácia
Vítejte v kalkulačce
Zadejte první číslo:
cislo
Neplatné číslo, zadejte prosím znovu:
13
Zadejte druhé číslo:
22
Zvolte si operaci:
1 - sčítání
2 - odčítání
3 - násobení
4 - dělení
3
Výsledek: 286.0
Přejete si zadat další příklad? [a/n]
n
Děkuji za použití kalkulačky.
Gratulujem, práve ste vytvorili svoj prvý blbovzdorný program:) Kód sa nám trochu skomplikoval, snáď ste to všetko pochytia. Niekedy v budúcnosti to treba napravíme a rozdelíme ho do prehľadných metód, pre tento kurz však považujme kalkulačku za hotovú, možno by sa do nej len mohlo pridať viac matematických funkcií, na tie sa v kurze tiež zameriame.
V budúcej lekcii, Zoznamy v Dart , sa opäť ponoríme do nových konštrukcií. Čakajú nás zoznamy a pokročilá práca s reťazcami. Potom to bude z konštrukcií v tejto sekcii všetko, blížime sa ku koncu.:)
Mal si s čímkoľvek problém? Stiahni si vzorovú aplikáciu nižšie a porovnaj ju so svojím projektom, chybu tak ľahko nájdeš.
Stiahnuť
Stiahnutím nasledujúceho súboru súhlasíš s licenčnými podmienkami
Stiahnuté 8x (2.81 kB)
Aplikácia je vrátane zdrojových kódov v jazyku Dart