diff --git a/priprava/rust_priprava11.md b/priprava/rust_priprava11.md new file mode 100644 index 0000000..d8e301f --- /dev/null +++ b/priprava/rust_priprava11.md @@ -0,0 +1,268 @@ +# clap → match → volanie metód — kde robíš chybu + +Tvoj problém nie je clap. Clap máš dobre. Tvoj problém je toto: + +```rust +Sc::DajKnihuIsbn { cesta, isbn } => { + Kniznica::daj_knihu_podla_isbn(isbn); // ZLE +} +``` + +Tri chyby na jednom riadku: +1. Nikde si nenačítal knižnicu zo súboru +2. Voláš metódu ako statickú (`Kniznica::`) namiesto na inštancii (`kniznica.`) +3. Ignoruješ návratovú hodnotu + +--- + +## Pravidlo 1: Najprv načítaj, potom volaj + +Metódy ako `daj_knihu_podla_isbn` sú `&self` metódy — potrebujú inštanciu. Tú musíš najprv vytvoriť z JSON súboru. + +```rust +// ZLE — Kniznica neexistuje, voláš na type +Kniznica::daj_knihu_podla_isbn(isbn); + +// DOBRE — najprv načítaj, potom volaj na inštancii +let kniznica = Kniznica::nacitaj_zo_suboru(&cesta).unwrap_or_default(); +kniznica.daj_knihu_podla_isbn(&isbn); +``` + +--- + +## Pravidlo 2: Statické vs inštančné metódy + +Pozri sa na signatúru metódy. To ti povie ako ju volať. + +```rust +// STATICKÁ metóda — nemá self, volaj cez Typ:: +fn nacitaj_zo_suboru(cesta: &PathBuf) -> Option +// Volanie: +let kniznica = Kniznica::nacitaj_zo_suboru(&cesta); + +// &self metóda — len čítanie, volaj cez instancia. +fn daj_knihu_podla_isbn(&self, isbn: &str) -> Option<&Kniha> +// Volanie: +let vysledok = kniznica.daj_knihu_podla_isbn(&isbn); + +// &mut self metóda — mení dáta, volaj cez mut instancia. +fn pridaj_knihu(&mut self, kniha: Kniha) -> Result<(), ()> +// Volanie: +let mut kniznica = Kniznica::nacitaj_zo_suboru(&cesta).unwrap_or_default(); +let vysledok = kniznica.pridaj_knihu(kniha); +``` + +Zhrnutie: + +| Signatúra | Čo potrebuješ | Volanie | +|-----------|---------------|---------| +| `fn nieco(cesta: &PathBuf)` — bez self | nič | `Kniznica::nieco(&cesta)` | +| `fn nieco(&self, ...)` | `let kniznica = ...` | `kniznica.nieco(...)` | +| `fn nieco(&mut self, ...)` | `let mut kniznica = ...` | `kniznica.nieco(...)` | + +--- + +## Pravidlo 3: Spracuj návratovú hodnotu + +Každá metóda niečo vracia. Musíš s tým niečo urobiť. + +```rust +// Option<&Kniha> — buď existuje, alebo nie +match kniznica.daj_knihu_podla_isbn(&isbn) { + Some(kniha) => println!("{}", kniha), + None => println!("Kniha nenájdená"), +} + +// Vec<&Kniha> — môže byť prázdny +let knihy = kniznica.daj_knihy_autora(&autor); +if knihy.is_empty() { + println!("Žiadne knihy"); +} else { + for kniha in &knihy { + println!("{}", kniha); + } +} + +// Result — podarilo sa alebo nie +match kniznica.odstran_knihu(&isbn) { + Ok(kniha) => println!("Odstránená: {}", kniha), + Err(()) => println!("Kniha nenájdená"), +} +``` + +--- + +## Pravidlo 4: Ak meníš dáta, ulož na konci + +```rust +// Čítacie metódy (&self) — NEUKLADAJ +Sc::DajKnihuIsbn { cesta, isbn } => { + let kniznica = Kniznica::nacitaj_zo_suboru(&cesta).unwrap_or_default(); + // daj_knihu_podla_isbn je &self — len číta + match kniznica.daj_knihu_podla_isbn(&isbn) { + Some(kniha) => println!("{}", kniha), + None => println!("Nenájdená"), + } + // ŽIADNE uloženie — nič sa nezmenilo +} + +// Meniace metódy (&mut self) — ULOŽ! +Sc::OdstranKnihu { cesta, isbn } => { + let mut kniznica = Kniznica::nacitaj_zo_suboru(&cesta).unwrap_or_default(); + // odstran_knihu je &mut self — mení dáta + match kniznica.odstran_knihu(&isbn) { + Ok(kniha) => { + println!("Odstránená: {}", kniha); + kniznica.uloz_do_suboru(&cesta); // ULOŽ ZMENY! + } + Err(()) => println!("Nenájdená"), + } +} +``` + +Keď uložiť: +- `pridaj_knihu` — áno (pridávaš) +- `odstran_knihu` — áno (mažeš) +- `daj_knihu_podla_isbn` — nie (len čítaš) +- `daj_knihy_autora` — nie +- `vypis_vydavatelstva_a_pocet_knih` — nie + +--- + +## Pravidlo 5: &isbn vs isbn — referencie v argumentoch + +Pozri sa čo metóda chce. Ak chce `&str`, daj referenciu na String. + +```rust +// Metóda chce: isbn: &str +fn daj_knihu_podla_isbn(&self, isbn: &str) -> Option<&Kniha> + +// Ty máš: isbn: String (z clapu) +// Volanie: +kniznica.daj_knihu_podla_isbn(&isbn) // & premení String na &str +``` + +Vždy keď metóda berie `&str` a ty máš `String`, daj `&`: + +```rust +kniznica.daj_knihu_podla_isbn(&isbn); // String → &str +kniznica.daj_knihy_autora(&autor); // String → &str +kniznica.odstran_knihu(&isbn); // String → &str +kniznica.daj_knihy_podla_stavu(stav); // Stav sa predáva priamo (nie referencia) +``` + +--- + +## Tvoj kód opravený + +```rust +use clap::{Parser, Subcommand}; +use std::path::PathBuf; +use riesenie1::Kniznica; + +#[derive(Parser, Debug)] +struct Args { + #[command(subcommand)] + cmd: Sc, +} + +#[derive(Subcommand, Debug)] +pub enum Sc { + DajKnihuIsbn { + cesta: PathBuf, + isbn: String, + }, + DajKnihyAutora { + cesta: PathBuf, + autor: String, + }, + OdstranKnihu { + cesta: PathBuf, + isbn: String, + }, + VypisVydavatelstva { + cesta: PathBuf, + }, +} + +fn main() { + let args = Args::parse(); + + match args.cmd { + Sc::DajKnihuIsbn { cesta, isbn } => { + // 1. Načítaj + let kniznica = Kniznica::nacitaj_zo_suboru(&cesta).unwrap_or_default(); + // 2. Zavolaj na inštancii + // 3. Spracuj výsledok + match kniznica.daj_knihu_podla_isbn(&isbn) { + Some(kniha) => println!("{}", kniha), + None => println!("Kniha s ISBN {} nenájdená", isbn), + } + } + Sc::DajKnihyAutora { cesta, autor } => { + let kniznica = Kniznica::nacitaj_zo_suboru(&cesta).unwrap_or_default(); + let knihy = kniznica.daj_knihy_autora(&autor); + if knihy.is_empty() { + println!("Žiadne knihy od autora {}", autor); + } else { + for kniha in &knihy { + println!("{}", kniha); + } + } + } + Sc::OdstranKnihu { cesta, isbn } => { + // mut! lebo odstran_knihu je &mut self + let mut kniznica = Kniznica::nacitaj_zo_suboru(&cesta).unwrap_or_default(); + match kniznica.odstran_knihu(&isbn) { + Ok(kniha) => { + println!("Odstránená: {}", kniha); + kniznica.uloz_do_suboru(&cesta); // ULOŽ! + } + Err(()) => println!("Kniha s ISBN {} nenájdená", isbn), + } + } + Sc::VypisVydavatelstva { cesta } => { + let kniznica = Kniznica::nacitaj_zo_suboru(&cesta).unwrap_or_default(); + // Táto metóda sama vypíše — len ju zavolaj + kniznica.vypis_vydavatelstva_a_pocet_knih(); + } + } +} +``` + +--- + +## Cvičenie: Doplň match arms + +Dopíš chýbajúce časti. Signatúry metód sú v komentároch. + +```rust +// SIGNATÚRY: +// fn nacitaj_zo_suboru(cesta: &PathBuf) -> Option +// fn uloz_do_suboru(&self, cesta: &PathBuf) -> bool +// fn pridaj(&mut self, kontakt: Kontakt) -> Result<(), ()> +// fn odstran(&mut self, meno: &str) -> Result +// fn hladaj(&self, meno: &str) -> Option<&Kontakt> +// fn vsetky(&self) -> Vec<&Kontakt> + +match args.cmd { + Sc::Pridaj { cesta, meno, telefon } => { + // TODO: načítaj (mut!), vytvor Kontakt, pridaj, ulož ak ok + } + Sc::Odstran { cesta, meno } => { + // TODO: načítaj (mut!), odstráň, vypíš výsledok, ulož ak ok + } + Sc::Hladaj { cesta, meno } => { + // TODO: načítaj, hľadaj, vypíš Some/None + } + Sc::Vypis { cesta } => { + // TODO: načítaj, zavolaj vsetky(), iteruj a vypíš + } +} +``` + +Skús to vyplniť sám. Ak nevieš, pozri na opravený kód vyššie — vzor je vždy rovnaký: +1. `let (mut) x = Typ::nacitaj_zo_suboru(&cesta).unwrap_or_default();` +2. `let vysledok = x.metoda(&arg);` +3. `match/if/for` na výsledku +4. Ak `&mut self` metóda → `x.uloz_do_suboru(&cesta);`