"if let" je pro me na prvni pohled celkem tezko pochopitelna konstrukce... vztahuje se ciste jen k Option a praci s nim, nebo ma vseobecnejsi pouziti?
Mozna me tam mate (pokud tomu spravne rozumim) ten implicitni pattern matching v prirazeni "Some(val) = result", coz je vec, ktera by v C-like jazycich nemohla existovat...
Jde o to, že pattern matching je možné použít i v normálním let, jenže v tomto případě si Rust hlídá, jestli jsou pokryty všechny možné varianty, což je dobře (tím se vyloučí naše javovské oblíbené NPE :-). Takže tento kód nelze přeložit, protože není pokryta varianta s None, jen se Some:
fn div(x: i32, y: i32) -> Option<i32> { if y != 0 { Some(x/y) } else { None } } fn main() { let Some(val) = div(2,1); println!("{}", val); }
Chybová hláška je celkem srozumitelná, ale už z ní není jasné, co použít:
error[E0005]: refutable pattern in local binding: `None` not covered
Řešením je právě if let, které si to ohlídá - v použití ve formě příkazu lze "else" vynechat, při použití jako výraz už ne:
fn div_message(x: i32, y :i32) -> String { let result = div(x, y); if let Some(val) = result { format!("{} / {} = {}", x, y, val) } } error[E0308]: if may be missing an else clause
Nějak jsem nepochopil ten rozdíl od C-čkového "#define MOJE_NAN MIN_INT a program plný podmínek testujících tuto speciální hodnotu" kontra "if let Some(val)= result"
V C běžně užívám (své definované makro/inline funkci) něco ve stylu
if NOTNAN(result=funkce(x,y)) { ...use result... } else { ...}
Případně přímo NOTNAN(result=funkce(x,y)) && (...use result...)
Jak se v Rust tedy omezí program plný podmínek. Lze nějak přímo použít Some(val), resp. unwrap, i když není definováno a výstupem je None? Nebo to v runtime také crashne, bez explicitní kontroly podmínkou na platnost? Má Rust nějakou implicitní ochranu navíc?
P.S.: V C++ bývá výhodnější const a inline funkce. Je to prakticky totéž, ale pro jistotu to (mmch už v compile time) ohlídá typy a odhalí mojí případnou chybu.
presne toto som sa tiez pytal sam seba ked som prechadzal z javy na scalu. Dobre je to hlavne ako nahrada za NULL hodnoty a to hned z dvoch dovodov:
1 - hned z deklaracie vidis, ze funkcia nemusi vratit hodnotu a nuti ta to tento stav osetrit (co v pripade zlej dokumentacie alebo lenivosti programatorov byva dost castym zdrojom chyb)
2 - prehladnost zapisu - ak mas napriklad zretazene 3 funkcie, z ktorych kazda je zavisla na vysledku tej predchadzajucej, v scale (a pravdepodobne aj v ruste) mozes spravit nieco taketo:
funkcia1().flatMap(res1 => funkcia2(result1)).flatMap(res2 => funkcia3(result3)).getOrElse(...)
co je imho omnoho elegantnejsie ako:
typ1 res1 = funkcia1();
if(typ1) {
res2 = funkcia2(res2);
if(res2)
res3 = funkcia3(res3);
if(res3)
return res3;
else ...
else...
else...
- O té jiné (upozorňující, varující) deklaraci jsem právě zkráceně mluvil v post scriptum. Do toho spadá i jiný typedef (a třeba i zákaz implicitní konverze). Případně až styl inline objekt /až template/ (s pouze inline funkcemi u kterých vím že se přeloží přímo). To je pak 100% ošetřené a v compile time (co jde). Což asi není nic jiného (ten extrémní případ) než totéž co dělá Rust. Jen to nechápu jako popis jazyka, ale prosté použití jazyka.
- Zřetězení funkcí ale funguje jen pro stejný typ. To používám také, pro objekty, kdy návratová hodnota je reference na objekt (sebe) /příp. návrat přímo hodnotou když vím že po kompilaci to vyjde výhodněji/ a stav si udržuji uvnitř. Je tak možné reagovat i na různé typy chybových stavů a třeba se lépe vzpamatovat.
Pro rozdílné typy je to && , tam už je jedno, jestli to "zřetězím" tečkou, ampersandem či jak. Styl, typová ochrana i výsledný překlad vyjdou nastejno.
První důležitý rozdíl spočívá v tom, že uživatele té funkce "donutíš" se zabývat speciálním stavem, takže nedojde k tomu, že se například napíše char c=getc()) a jede se klidně dál.
K tomu zjednodušení - když se použije zřetězení přes and_then, and, unwrap_or atd, tak je to částečné zjednodušení, ovšem užitečnější jsou například funkce map_or, map_or_else, umožňující skutečně zřetězení (s transformací hodnot na jiné typy). Zkusím ukázat.
Díky moc, právě jsem si psal odpověď na základě Vaší odpovědi na první otázku na fóru. :-D
Teď už výhodě Option jasně rozumím. A považuji jej za _velmi_ přínosný. I kdyby už nebyly i žádně další výhody (zřetězení, ...). Chybu už v compile time, že jsem návratový chybový stav neohlídal, považuji za věc k nezaplacení.
P.S.: Tisíceré díky za seriál.