Files
JR-priprava-na-skusku/priprava/rust_priprava15.md
2026-03-06 08:02:25 +01:00

8.2 KiB

Ok, ok(), is_ok(), () — rýchlokurz


1. Dva svety: Result a Option

Result<T, E>  →  Ok(hodnota)  alebo  Err(chyba)
Option<T>     →  Some(hodnota) alebo  None

Result používaš keď chceš vedieť ČO sa pokazilo. Option keď ťa zaujíma len či niečo existuje alebo nie.


2. Čo je ()

() je "unit type" — prázdna hodnota. Znamená "nič zaujímavé".

// Funkcia, ktorá nič nevracia, v skutočnosti vracia ()
fn pozdrav() {
    println!("ahoj");
}
// je to isté ako:
fn pozdrav() -> () {
    println!("ahoj");
}

3. Ok(()) — úspech bez hodnoty

Keď metóda buď uspeje (ale nemá čo vrátiť) alebo zlyhá:

fn pridaj_knihu(&mut self, kniha: Kniha) -> Result<(), ()> {
    if self.knihy.iter().any(|k| k.nazov == kniha.nazov) {
        return Err(());   // zlyhalo — duplikát
    }
    self.knihy.push(kniha);
    Ok(())                // úspech — ale nemám čo vrátiť, tak ()
}

Ok(()) = "podarilo sa, nemám ti čo dať". Err(()) = "nepodarilo sa, a ani ti nepoviem prečo".

Kedy Result<(), ()>

Keď nepotrebuješ ani návratovú hodnotu ani detail chyby:

fn pridaj(&mut self, meno: &str) -> Result<(), ()> { ... }
fn nastav(&mut self, hodnota: u32) -> Result<(), ()> { ... }

Kedy Result<T, ()>

Keď pri úspechu vraciaš niečo, ale chyba nemá detail:

fn odstran(&mut self, meno: &str) -> Result<Kniha, ()> { ... }
// Ok(kniha) — tu je odstránená kniha
// Err(()) — nenašiel som ju

Kedy Result<T, String>

Keď chceš popísať chybu:

fn pridaj(&mut self, kniha: Kniha) -> Result<(), String> {
    if self.knihy.iter().any(|k| k.nazov == kniha.nazov) {
        return Err(format!("Kniha '{}' už existuje", kniha.nazov));
    }
    self.knihy.push(kniha);
    Ok(())
}

4. .ok() — Result → Option (zahoď chybu)

.ok() premení Result na Option. Ak bol Err, zahodí chybu a dá None:

Result<T, E>    .ok()    Option<T>

Ok(42)          .ok()    Some(42)
Err("chyba")    .ok()    None
// Prakticky:
let cislo: Result<i32, _> = "42".parse();
let cislo: Option<i32> = "42".parse().ok();   // Some(42)
let cislo: Option<i32> = "abc".parse().ok();  // None

// Súborový I/O:
let obsah: Result<String, io::Error> = fs::read_to_string("data.json");
let obsah: Option<String> = fs::read_to_string("data.json").ok();

Kedy: Keď ťa nezaujíma detail chyby, len či sa podarilo.


5. .ok()? — najčastejší vzor na skúške

.ok() + ? spolu — premení Result na Option a ak je None, vráti None z funkcie:

fn nacitaj_zo_suboru(cesta: &PathBuf) -> Option<Kniznica> {
    let raw = fs::read_to_string(cesta).ok()?;
    //        ^^^^^^^^^^^^^^^^^^^^^^^^^ Result<String, Error>
    //                                  .ok() → Option<String>
    //                                       ? → ak None, return None; ak Some, rozbaľ
    serde_json::from_str(&raw).ok()
    //                         ^^^ posledný riadok — .ok() premení na Option, vráti sa
}

Rozklad:

Súbor existuje:
  fs::read_to_string → Ok("{ ... }")
  .ok()              → Some("{ ... }")
  ?                  → "{ ... }"         (rozbalí Some)
  serde_json::from_str → Ok(Kniznica{...})
  .ok()              → Some(Kniznica{...})
  → funkcia vráti Some(Kniznica{...})

Súbor neexistuje:
  fs::read_to_string → Err(io::Error)
  .ok()              → None
  ?                  → return None       (okamžite opustí funkciu)

6. .is_ok() a .is_err() — bool kontrola

let vysledok: Result<i32, String> = Ok(42);

vysledok.is_ok()   // true
vysledok.is_err()  // false

let vysledok: Result<i32, String> = Err("chyba".into());

vysledok.is_ok()   // false
vysledok.is_err()  // true

Hlavné použitie — ukladanie:

fn uloz_do_suboru(&self, cesta: &PathBuf) -> bool {
    let Ok(json) = serde_json::to_string_pretty(&self) else {
        return false;
    };
    fs::write(cesta, json).is_ok()
    //                     ^^^^^^ Result → bool
    //                     úspech → true, chyba → false
}

fs::write vracia Result<(), Error>. Nás zaujíma len "podarilo sa?" → .is_ok()bool.


7. .ok_or() a .ok_or_else() — Option → Result

Opačný smer: máš Option, chceš Result.

Option<T>    .ok_or(chyba)    Result<T, E>

Some(42)     .ok_or("nič")    Ok(42)
None         .ok_or("nič")    Err("nič")
// Prakticky — position vracia Option, ty chceš Result
fn odstran(&mut self, meno: &str) -> Result<String, ()> {
    let pos = self.mena.iter().position(|m| m == meno).ok_or(())?;
    //        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Option<usize>
    //                                                .ok_or(()) → Result<usize, ()>
    //                                                          ? → ak Err, return Err
    Ok(self.mena.remove(pos))
}
// ok_or_else — lazy verzia (closure sa zavolá len ak None)
fn najdi(&self, meno: &str) -> Result<&Kniha, String> {
    self.knihy.iter()
        .find(|k| k.nazov == meno)
        .ok_or_else(|| format!("Kniha '{}' nenájdená", meno))
}

8. .unwrap_or() a .unwrap_or_default() — fallback hodnota

// Option
let cislo: Option<i32> = None;
cislo.unwrap_or(0)         // 0 — fallback
cislo.unwrap_or_default()  // 0 — default pre i32

// Result
let cislo: Result<i32, _> = "abc".parse();
cislo.unwrap_or(0)         // 0 — fallback
cislo.unwrap_or_default()  // 0

// Na skúške — načítanie s fallbackom
let kniznica = Kniznica::nacitaj_zo_suboru(&cesta)  // Option<Kniznica>
    .unwrap_or_default();                             // Kniznica::default() ak None

9. let...else — rozbaľ alebo odíď

// Ak je Ok, rozbaľ do premennej. Ak Err, vykonaj blok (musí divergovať — return/break/continue).
let Ok(json) = serde_json::to_string_pretty(&self) else {
    return false;
};
// tu json je String

// Ak je Some, rozbaľ. Ak None, odíď.
let Some(kniha) = self.knihy.iter().find(|k| k.nazov == nazov) else {
    return None;
};
// tu kniha je &Kniha

10. Veľký prehľad: čo kedy

Mám Result, chcem...

Chcem Použi Príklad
Option (zahodiť chybu) .ok() "42".parse().ok()Some(42)
bool (podarilo sa?) .is_ok() fs::write(c, d).is_ok()true
Rozbaľ alebo vráť None .ok()? fs::read_to_string(c).ok()?
Rozbaľ alebo panic .unwrap() len v testoch!
Rozbaľ alebo fallback .unwrap_or(val) vstup.parse().unwrap_or(0)
Rozbaľ alebo default .unwrap_or_default() nacitaj().unwrap_or_default()
Rozbaľ alebo return let Ok(x) = ... else { return } serializácia v uloz

Mám Option, chcem...

Chcem Použi Príklad
Result (pridať chybu) .ok_or(err) vec.find(x).ok_or(())
Rozbaľ alebo vráť None ? slovnik.get(kat)?
bool (existuje?) .is_some() / .is_none() mapa.get("x").is_some()
Rozbaľ alebo fallback .unwrap_or(val) mapa.get("x").unwrap_or(&0)
Rozbaľ alebo default .unwrap_or_default() nacitaj().unwrap_or_default()
Rozbaľ alebo return let Some(x) = ... else { return }

Chcem vrátiť z funkcie...

Návratový typ Úspech Zlyhanie
Result<(), ()> Ok(()) Err(())
Result<T, ()> Ok(hodnota) Err(())
Result<(), String> Ok(()) Err("popis".into())
Result<T, String> Ok(hodnota) Err(format!("..."))
Option<T> Some(hodnota) None
bool true false

Konverzie — kompletná mapa

Result<T, E> ──.ok()──────→ Option<T>       (zahodí E)
Result<T, E> ──.is_ok()───→ bool
Result<T, E> ──.is_err()──→ bool

Option<T> ──.ok_or(e)─────→ Result<T, E>    (pridá E)
Option<T> ──.is_some()────→ bool
Option<T> ──.is_none()────→ bool

Result<T, E> ──.unwrap_or(val)────→ T
Option<T>    ──.unwrap_or(val)────→ T

Result<T, E> ──.unwrap_or_default()──→ T    (T: Default)
Option<T>    ──.unwrap_or_default()──→ T    (T: Default)