# Rust — Iterátory, Closures, Kombinácie (D–G) Pre každú tému: **vysvetlenie** → **príklady** → **úlohy na precvičenie** → riešenia na konci. --- ## Časť D: Iterátory ### D.1 — Čo je iterátor Iterátor je spôsob, ako prejsť cez kolekciu prvok po prvku. V Ruste existujú 3 spôsoby ako získať iterátor z kolekcie: | Metóda | Dáva ti | Kedy použiť | |--------|---------|-------------| | `.iter()` | `&T` (nemeniteľná referencia) | Chceš len čítať | | `.iter_mut()` | `&mut T` (meniteľná referencia) | Chceš meniť prvky na mieste | | `.into_iter()` | `T` (vlastníctvo) | Chceš konzumovať kolekciu | ```rust let mut cisla = vec![1, 2, 3]; // iter() — len čítam, cisla existujú ďalej for c in cisla.iter() { println!("{}", c); // c je &i32 } // iter_mut() — mením prvky for c in cisla.iter_mut() { *c += 10; // c je &mut i32, treba dereferencovať } // cisla je teraz [11, 12, 13] // into_iter() — preberám vlastníctvo, cisla po tomto neexistujú let cisla2 = vec![1, 2, 3]; for c in cisla2.into_iter() { println!("{}", c); // c je i32 } // cisla2 tu už nemôžeš použiť! ``` **Pravidlo:** Ak máš `&self` metódu (len čítaš), použi `.iter()`. Ak máš `&mut self`, použi `.iter_mut()`. --- ### D.2 — filter **Čo robí:** Prejde cez iterátor a nechá len prvky, pre ktoré closure vráti `true`. **Typ:** `.filter()` dáva referencie na referencie. Ak iteruješ cez `&T`, vo filtri dostaneš `&&T`. ```rust let cisla = vec![1, 2, 3, 4, 5, 6]; // Nechaj len párne let parne: Vec<&i32> = cisla.iter().filter(|c| *c % 2 == 0).collect(); // parne = [&2, &4, &6] // Ak chceš Vec (nie referencie), použi .copied() alebo .cloned() let parne: Vec = cisla.iter().filter(|c| *c % 2 == 0).copied().collect(); // parne = [2, 4, 6] ``` **So štruktúrami:** ```rust struct Kniha { nazov: String, rok: u16 } let knihy = vec![ Kniha { nazov: "A".into(), rok: 2020 }, Kniha { nazov: "B".into(), rok: 2015 }, ]; // Knihy po roku 2018 let nove: Vec<&Kniha> = knihy.iter().filter(|k| k.rok > 2018).collect(); ``` **Na skúške:** Každá metóda typu `daj_knihy_podla_X` je `filter` + `collect`. --- ### D.3 — find **Čo robí:** Vráti **prvý** prvok, pre ktorý closure vráti `true`. Vráti `Option`. ```rust let cisla = vec![1, 2, 3, 4, 5]; let prve_parne: Option<&i32> = cisla.iter().find(|c| *c % 2 == 0); // Some(&2) let viac_ako_10: Option<&i32> = cisla.iter().find(|c| **c > 10); // None ``` **So štruktúrami:** ```rust let knihy = vec![ Kniha { nazov: "Hobbit".into(), rok: 1937 }, Kniha { nazov: "Duna".into(), rok: 1965 }, ]; // Nájdi knihu podľa názvu let najdena: Option<&Kniha> = knihy.iter().find(|k| k.nazov == "Duna"); ``` **Na skúške:** Každá metóda typu `daj_knihu_podla_isbn` je `find`. --- ### D.4 — position **Čo robí:** Ako `find`, ale vráti **index** namiesto hodnoty. Vráti `Option`. ```rust let mena = vec!["Anna".to_string(), "Boris".to_string(), "Cyril".to_string()]; let index: Option = mena.iter().position(|m| m == "Boris"); // Some(1) ``` **Hlavné použitie — odstránenie z Vec:** ```rust fn odstran(zoznam: &mut Vec, meno: &str) -> Result { // 1. nájdi index let pos = zoznam.iter().position(|s| s == meno).ok_or(())?; // 2. odstráň na tom indexe (remove posunie zvyšné prvky) Ok(zoznam.remove(pos)) } ``` **Na skúške:** Každá metóda `odstran_knihu`, `odstran_kontakt` atď. je `position` + `remove`. --- ### D.5 — map **Čo robí:** Transformuje každý prvok. `[A, B, C]` → `[f(A), f(B), f(C)]`. ```rust let cisla = vec![1, 2, 3]; // Zdvojnásob každé let dvojnasobok: Vec = cisla.iter().map(|c| c * 2).collect(); // [2, 4, 6] // Prevod na String let texty: Vec = cisla.iter().map(|c| c.to_string()).collect(); // ["1", "2", "3"] // Vytiahni pole zo štruktúry let nazvy: Vec<&String> = knihy.iter().map(|k| &k.nazov).collect(); ``` --- ### D.6 — any a all **Čo robia:** Vracajú `bool`. ```rust let cisla = vec![1, -2, 3, -4, 5]; // any — existuje aspoň jeden, pre ktorý platí? let ma_zaporne: bool = cisla.iter().any(|c| *c < 0); // true // all — platí pre VŠETKY? let vsetky_kladne: bool = cisla.iter().all(|c| *c > 0); // false ``` --- ### D.7 — sum a count ```rust let cisla = vec![1, 2, 3, 4, 5]; // Súčet — musíš špecifikovať typ let sucet: i32 = cisla.iter().sum(); // alebo let sucet = cisla.iter().sum::(); // 15 // Počet prvkov spĺňajúcich podmienku let pocet_parnych: usize = cisla.iter().filter(|c| *c % 2 == 0).count(); // 2 ``` --- ### D.8 — max_by_key a min_by_key **Čo robí:** Nájde maximum/minimum podľa kľúča. Vráti `Option`. ```rust struct Zamestnanec { meno: String, plat: u32 } let zamestnanci = vec![ Zamestnanec { meno: "Anna".into(), plat: 3000 }, Zamestnanec { meno: "Boris".into(), plat: 4500 }, Zamestnanec { meno: "Cyril".into(), plat: 2800 }, ]; let najbohatsi: Option<&Zamestnanec> = zamestnanci.iter().max_by_key(|z| z.plat); // Some(Boris) ``` --- ### D.9 — enumerate **Čo robí:** Pridá index ku každému prvku. `[A, B, C]` → `[(0, A), (1, B), (2, C)]`. ```rust let mena = vec!["Anna", "Boris", "Cyril"]; for (i, meno) in mena.iter().enumerate() { println!("{}. {}", i + 1, meno); } // 1. Anna // 2. Boris // 3. Cyril ``` --- ### D.10 — Reťazenie Iterátory sa dajú reťaziť. Každá metóda vráti nový iterátor: ```rust let zamestnanci = vec![/* ... */]; // Mená zamestnancov s platom nad 3000, zoradené let bohati_mena: Vec<&String> = zamestnanci.iter() .filter(|z| z.plat > 3000) // nechaj len bohatých .map(|z| &z.meno) // vytiahni meno .collect(); // zhromaždi do Vec ``` **Kedy for, kedy iterátor:** - Jednoduchý prechod s výpisom → `for` - Filtrovanie → `.filter().collect()` - Transformácia → `.map().collect()` - Hľadanie → `.find()` alebo `.position()` - Podmienka → `.any()` alebo `.all()` - Počítanie → `.filter().count()` - Ak robíš kombináciu hore → reťaz iterátorov --- ### Úlohy D **D-1.** Máš `Vec` = `[3, -1, 4, -1, 5, 9, -2, 6]`. Napíš jedným výrazom (bez for): - a) Počet kladných čísel - b) Súčet záporných čísel - c) Vec len kladných čísel (ako `Vec`, nie referencie) - d) Či sú všetky čísla väčšie ako -5 - e) Či existuje číslo väčšie ako 8 **D-2.** Máš: ```rust struct Student { meno: String, vek: u8, priemer: f32 } let studenti: Vec = /* ... */; ``` Napíš (každé na jeden riadok): - a) Mená študentov s priemerom pod 2.0 → `Vec<&String>` - b) Najstarší študent → `Option<&Student>` - c) Priemerný vek všetkých študentov → `Option` - d) Existuje študent mladší ako 18? → `bool` - e) Odstráň študenta podľa mena z `&mut Vec` → `Result` **D-3.** Prepíš na iterátorový zápis bez `for` a bez `mut` premenných: ```rust fn kladne_zdvojnasobene(cisla: &[i32]) -> Vec { let mut vysledok = Vec::new(); for c in cisla { if *c > 0 { vysledok.push(c * 2); } } vysledok } ``` **D-4.** Čo je zle? Oprav: ```rust fn zvys_vsetky(cisla: &mut Vec) { for c in cisla.iter() { *c += 1; } } ``` --- ## Časť E: Closures (uzávery) ### E.1 — Čo je closure Closure je anonymná funkcia, ktorá môže zachytiť premenné z okolitého prostredia. ```rust // Normálna funkcia — nemá prístup k okoliu fn pricti_5(x: i32) -> i32 { x + 5 } // Closure — zachytí premennú `zaklad` z okolia let zaklad = 5; let pricti = |x: i32| -> i32 { x + zaklad }; println!("{}", pricti(10)); // 15 ``` ### E.2 — Syntax closure Od najdlhšieho po najkratšie: ```rust // Plný zápis (ako funkcia, ale s ||) let f = |x: i32, y: i32| -> i32 { x + y }; // Bez typov (Rust si ich odvodí) let f = |x, y| { x + y }; // Bez zátvoriek (ak je len jeden výraz) let f = |x, y| x + y; // Bez parametrov let f = || println!("ahoj"); // S jedným parametrom let f = |x| x * 2; ``` **Pravidlo:** V `.filter()`, `.map()`, `.find()` atď. vždy píš najkratší zápis. ### E.3 — Closures v iterátoroch Toto sú najčastejšie situácie: ```rust let cisla = vec![1, 2, 3, 4, 5]; // filter — closure berie &&T (referenciu na referenciu) cisla.iter().filter(|c| **c > 3) // c je &&i32, treba ** cisla.iter().filter(|&c| *c > 3) // destructuring v parametri cisla.iter().filter(|&&c| c > 3) // plný destructuring // map — closure berie &T cisla.iter().map(|c| c * 2) // c je &i32, Rust automaticky dereferencuje pri * // find — rovnako ako filter cisla.iter().find(|c| **c == 3) // any/all — rovnako ako filter cisla.iter().any(|c| *c > 3) // tu je len &T, nie &&T! ``` **Prečo filter má `&&T`?** Lebo `.iter()` dáva `&T`, a filter ešte obalí ďalšou referenciou. Ale Rust je v praxi dosť chytrý — väčšinou stačí `|c| c > &3` alebo `|c| *c > 3`. ### E.4 — move closure Normálne closure zachytáva referencie. `move` prenesie vlastníctvo do closure: ```rust // BEZ move — closure zachytí &meno let meno = "Anna".to_string(); let pozdrav = || println!("Ahoj {}", meno); pozdrav(); println!("{}", meno); // OK, meno stále existuje // S move — closure prevezme vlastníctvo mena let meno = "Anna".to_string(); let pozdrav = move || println!("Ahoj {}", meno); pozdrav(); // println!("{}", meno); // CHYBA! meno bolo presunuté do closure ``` **Kedy treba move:** Keď closure musí prežiť pôvodnú premennú (napr. vrátenie closure z funkcie). ```rust fn vytvor_pozdrav(meno: String) -> impl Fn() { // BEZ move: CHYBA — meno zomrie na konci funkcie, ale closure ho referencuje // S move: OK — closure vlastní meno move || println!("Ahoj {}", meno) } ``` ### E.5 — Closure zachytávajúci &mut Ak closure modifikuje premennú, zachytí ju ako `&mut`: ```rust let mut pocitadlo = 0; let mut zvys = || { pocitadlo += 1; }; zvys(); zvys(); zvys(); println!("{}", pocitadlo); // 3 ``` **Dôležité:** Kým existuje `&mut` closure, nemôžeš čítať premennú inak: ```rust let mut cisla = vec![1, 2, 3]; let mut pridaj = |x| cisla.push(x); pridaj(4); // println!("{:?}", cisla); // CHYBA TU! pridaj stále drží &mut cisla pridaj(5); drop(pridaj); // explicitne uvoľni closure println!("{:?}", cisla); // OK teraz — [1, 2, 3, 4, 5] ``` Alebo jednoducho — posledné použitie closure pred prvým iným použitím: ```rust let mut cisla = vec![1, 2, 3]; let mut pridaj = |x| cisla.push(x); pridaj(4); pridaj(5); // posledné volanie println!("{:?}", cisla); // OK — Rust vie, že pridaj sa už nepoužije ``` --- ### Úlohy E **E-1.** Napíš 3 verzie tej istej operácie (vyfiltruj čísla > 10 z Vec): - a) S pomenovanou funkciou (nie closure) - b) S plným zápisom closure (aj typy) - c) S najkratším zápisom **E-2.** Čo je zle? Oprav: ```rust fn vrat_nasobicku(faktor: i32) -> impl Fn(i32) -> i32 { |x| x * faktor } ``` **E-3.** Napíš funkciu `aplikuj_na_vsetky(cisla: &[i32], f: impl Fn(i32) -> i32) -> Vec` ktorá aplikuje funkciu `f` na každý prvok. Potom ju zavolaj s: - a) closure, ktorý zdvojnásobí - b) closure, ktorý pripočíta 100 - c) pomenovanou funkciou, ktorá vráti absolútnu hodnotu **E-4.** Máš `Vec`. Napíš closure, ktorý: - Zachytí `&mut Vec` - Pridá reťazec do vektora - Zavolaj ho 3x, potom vypíš výsledok --- ## Časť F: HashMap ### F.1 — Základy ```rust use std::collections::HashMap; let mut mapa: HashMap = HashMap::new(); // Vloženie mapa.insert("Anna".to_string(), 25); mapa.insert("Boris".to_string(), 30); // Čítanie — vráti Option<&V> let vek: Option<&i32> = mapa.get("Anna"); // Some(&25) let vek: Option<&i32> = mapa.get("Cyril"); // None // Kontrola existencie let existuje: bool = mapa.contains_key("Anna"); // true // Iterácia for (meno, vek) in &mapa { println!("{}: {}", meno, vek); } ``` ### F.2 — Entry API (dôležité na skúške!) `entry()` je spôsob, ako pracovať s kľúčom, ktorý môže alebo nemusí existovať: ```rust use std::collections::HashMap; let mut pocty: HashMap = HashMap::new(); let slova = vec!["ahoj", "svet", "ahoj", "rust", "svet", "ahoj"]; // Počítaj výskyty for slovo in &slova { // entry() vráti Entry — buď Occupied alebo Vacant // or_insert(0) — ak kľúč neexistuje, vlož 0 // vráti &mut hodnotu *pocty.entry(slovo.to_string()).or_insert(0) += 1; } // pocty = {"ahoj": 3, "svet": 2, "rust": 1} ``` **Rozklad:** ```rust *pocty.entry(slovo.to_string()).or_insert(0) += 1; // ^^^^^ nájdi alebo vytvor kľúč // ^^^^^^^^^^^^ ak neexistuje, vlož 0 // ^^^^ vráti &mut usize // ^^^ += 1 dereferencuj a zvýš ``` **Na skúške:** Metódy ako `vypis_vydavatelstva_a_pocet_knih` alebo `pocet_v_kategoriach` vždy používajú tento vzor. ### F.3 — HashMap zo štruktúr Typický vzor na skúške — zoskup podľa poľa a spočítaj: ```rust struct Kniha { nazov: String, vydavatelstvo: String } fn pocty_podla_vydavatelstva(knihy: &[Kniha]) -> HashMap { let mut mapa = HashMap::new(); for kniha in knihy { *mapa.entry(kniha.vydavatelstvo.clone()).or_insert(0) += 1; } mapa } // Výpis: fn vypis_statistiky(knihy: &[Kniha]) { let pocty = pocty_podla_vydavatelstva(knihy); for (vydavatelstvo, pocet) in &pocty { println!("{}: {}", vydavatelstvo, pocet); } } ``` ### F.4 — or_insert_with a or_default ```rust // or_insert_with — lazy verzia, closure sa zavolá len ak kľúč neexistuje mapa.entry(kluc).or_insert_with(|| Vec::new()); // or_default — použije Default trait // Pre Vec → prázdny vektor, pre usize → 0, pre String → "" mapa.entry(kluc).or_default(); // Príklad: zoskupenie kníh podľa žánru let mut podla_zanru: HashMap> = HashMap::new(); for kniha in &knihy { podla_zanru.entry(kniha.zaner.clone()).or_default().push(kniha); } ``` --- ### Úlohy F **F-1.** Napíš funkciu `pocitaj_znaky(text: &str) -> HashMap` — počet výskytov každého znaku. **F-2.** Máš `Vec` kde Student má `meno`, `trieda: String`, `priemer: f32`. Napíš: - a) `pocet_v_triedach(studenti: &[Student]) -> HashMap` — koľko študentov v každej triede - b) `najlepsi_v_triede(studenti: &[Student]) -> HashMap` — študent s najnižším priemerom v každej triede **F-3.** Napíš funkciu `invertuj_mapu(mapa: &HashMap) -> HashMap` — otočí kľúče a hodnoty. --- ## Časť G: Option/Result kombinátory ### G.1 — .map() na Option **Čo robí:** Ak je `Some(x)`, aplikuje funkciu na `x`. Ak `None`, zostane `None`. ```rust let a: Option = Some(5); let b: Option = None; let a2: Option = a.map(|x| x * 2); // Some(10) let b2: Option = b.map(|x| x * 2); // None // Praktické — vytiahni pole zo Option<&Struct> let kniha: Option<&Kniha> = najdi_knihu("Duna"); let nazov: Option<&String> = kniha.map(|k| &k.nazov); // Prevod typu let cislo: Option = Some(42); let text: Option = cislo.map(|c| c.to_string()); // Some("42") ``` **Nahrádza:** ```rust // Toto: match opt { Some(x) => Some(f(x)), None => None, } // Je to isté ako: opt.map(f) ``` ### G.2 — .and_then() (flatmap) **Čo robí:** Ako `.map()`, ale closure vracia `Option`. Zabraňuje `Option>`. ```rust // map by vytvorilo Option>: let text: Option = Some("42".to_string()); let zle: Option> = text.map(|t| t.parse::().ok()); // and_then "sploští": let text: Option = Some("42".to_string()); let dobre: Option = text.and_then(|t| t.parse::().ok()); // Some(42) let text2: Option = Some("abc".to_string()); let dobre2: Option = text2.and_then(|t| t.parse::().ok()); // None (parse zlyhalo) ``` **Pravidlo:** Ak tvoja closure vracia `Option` → použi `.and_then()`. Ak vracia holú hodnotu → použi `.map()`. ### G.3 — .map_err() **Čo robí:** Transformuje chybu v `Result`, hodnotu necháva. ```rust // read_to_string vracia Result // Ty chceš Result fn nacitaj(cesta: &str) -> Result { std::fs::read_to_string(cesta) .map_err(|e| format!("Chyba čítania: {}", e)) } ``` ### G.4 — .flatten() **Čo robí:** `Option>` → `Option`, `Result, E>` → `Result`. ```rust let a: Option> = Some(Some(5)); let b: Option> = Some(None); let c: Option> = None; a.flatten() // Some(5) b.flatten() // None c.flatten() // None ``` ### G.5 — .unwrap_or(), .unwrap_or_default(), .unwrap_or_else() ```rust let a: Option = None; a.unwrap_or(0) // 0 — vždy vyhodnotí fallback a.unwrap_or_default() // 0 — použije Default trait (i32 default = 0) a.unwrap_or_else(|| { // lazy — closure sa zavolá len ak None println!("Počítam fallback..."); vypocitaj_nieco() }) ``` **Kedy ktorý:** - `.unwrap_or(hodnota)` — fallback je jednoduchá konštanta - `.unwrap_or_default()` — chceš default pre daný typ (0, "", Vec::new(), false) - `.unwrap_or_else(|| ...)` — fallback je drahý výpočet --- ### Úlohy G **G-1.** Prepíš bez `match`: ```rust fn zdvojnasob_option(x: Option) -> Option { match x { Some(n) => Some(n * 2), None => None, } } ``` **G-2.** Prepíš bez `match`: ```rust fn parsuj_prvy_znak(text: Option) -> Option { match text { Some(t) => { match t.chars().next() { Some(c) => Some(c), None => None, } } None => None, } } ``` **G-3.** Napíš funkciu `bezpecne_delenie(a: f64, b: f64) -> Option` — vráti `None` ak `b == 0.0`. Bez `if`, použi `.filter()` alebo podmienku v `.and_then()`. Potom napíš: `delenie_s_fallbackom(a: f64, b: f64) -> f64` — ak sa nedá deliť, vráti `0.0`. Použi predošlú funkciu + `.unwrap_or()`. **G-4.** Máš: ```rust fn najdi_pouzivatela(id: u32) -> Option { /* ... */ } fn najdi_email(meno: &str) -> Option { /* ... */ } ``` Napíš funkciu `email_pre_id(id: u32) -> Option` — nájdi použivateľa podľa id, potom jeho email. Jeden riadok s `.and_then()`. **G-5.** Čo vypíše? Najprv tipni, potom over: ```rust let a: Option = Some(5); println!("{:?}", a.map(|x| x > 3)); println!("{:?}", a.filter(|x| *x > 3)); println!("{:?}", a.filter(|x| *x > 10)); println!("{:?}", a.map(|x| x.to_string())); println!("{:?}", a.and_then(|x| if x > 3 { Some(x * 2) } else { None })); ``` --- ## Časť H: Kombinované cvičenia (simulácia skúšky) ### H-1. Kompletný CRUD Implementuj bez pozerania na čokoľvek: ```rust use serde::{Serialize, Deserialize}; use std::collections::HashMap; #[derive(Serialize, Deserialize, Clone)] struct Produkt { nazov: String, cena: f64, kategoria: String, na_sklade: bool, } #[derive(Serialize, Deserialize, Default)] struct Obchod { produkty: Vec, } impl Obchod { fn nacitaj_zo_suboru(cesta: &std::path::PathBuf) -> Option { todo!() } fn uloz_do_suboru(&self, cesta: &std::path::PathBuf) -> bool { todo!() } fn pridaj(&mut self, produkt: Produkt) -> Result<(), ()> { todo!() } // duplicita podľa nazvu fn odstran(&mut self, nazov: &str) -> Result { todo!() } fn najdi(&self, nazov: &str) -> Option<&Produkt> { todo!() } fn na_sklade(&self) -> Vec<&Produkt> { todo!() } fn v_kategorii(&self, kat: &str) -> Vec<&Produkt> { todo!() } fn najdrahsi(&self) -> Option<&Produkt> { todo!() } fn priemerny_cena_v_kategorii(&self, kat: &str) -> Option { todo!() } fn pocty_kategorii(&self) -> HashMap { todo!() } } ``` ### H-2. Display enum + struct ```rust use std::fmt; enum Velkost { Mala, Stredna, Velka } // Implementuj Display: "S", "M", "L" struct Tricko { farba: String, velkost: Velkost, cena: f64 } // Implementuj Display: "Tričko [M] červené - 19.99€" ``` --- --- --- # RIEŠENIA ## D-1 ```rust let cisla = vec![3, -1, 4, -1, 5, 9, -2, 6]; // a) let pocet_kladnych: usize = cisla.iter().filter(|c| **c > 0).count(); // 5 // b) let sucet_zapornych: i32 = cisla.iter().filter(|c| **c < 0).sum(); // -4 // c) let kladne: Vec = cisla.iter().filter(|c| **c > 0).copied().collect(); // [3, 4, 5, 9, 6] // d) let vsetky_nad_minus5: bool = cisla.iter().all(|c| *c > -5); // true // e) let existuje_nad_8: bool = cisla.iter().any(|c| *c > 8); // true ``` ## D-2 ```rust struct Student { meno: String, vek: u8, priemer: f32 } // a) let mena: Vec<&String> = studenti.iter().filter(|s| s.priemer < 2.0).map(|s| &s.meno).collect(); // b) let najstarsi: Option<&Student> = studenti.iter().max_by_key(|s| s.vek); // c) fn priemerny_vek(studenti: &[Student]) -> Option { if studenti.is_empty() { return None; } let sucet: u32 = studenti.iter().map(|s| s.vek as u32).sum(); Some(sucet as f64 / studenti.len() as f64) } // d) let ma_mladsiho: bool = studenti.iter().any(|s| s.vek < 18); // e) fn odstran_studenta(studenti: &mut Vec, meno: &str) -> Result { let pos = studenti.iter().position(|s| s.meno == meno).ok_or(())?; Ok(studenti.remove(pos)) } ``` ## D-3 ```rust fn kladne_zdvojnasobene(cisla: &[i32]) -> Vec { cisla.iter().filter(|c| **c > 0).map(|c| c * 2).collect() } ``` ## D-4 `iter()` dáva `&i32` (nemeniteľná referencia). Nemôžeš cez ňu meniť. Treba `iter_mut()`: ```rust fn zvys_vsetky(cisla: &mut Vec) { for c in cisla.iter_mut() { *c += 1; } } ``` ## E-1 ```rust let cisla = vec![1, 5, 12, 3, 15, 8]; // a) pomenovaná funkcia fn je_viac_ako_10(c: &&i32) -> bool { **c > 10 } let vysledok: Vec<&i32> = cisla.iter().filter(je_viac_ako_10).collect(); // b) plný zápis let vysledok: Vec<&i32> = cisla.iter().filter(|c: &&i32| -> bool { **c > 10 }).collect(); // c) najkratší let vysledok: Vec<&i32> = cisla.iter().filter(|c| **c > 10).collect(); ``` ## E-2 Treba `move` — `faktor` je lokálna premenná, closure ho musí vlastniť: ```rust fn vrat_nasobicku(faktor: i32) -> impl Fn(i32) -> i32 { move |x| x * faktor } ``` ## E-3 ```rust fn aplikuj_na_vsetky(cisla: &[i32], f: impl Fn(i32) -> i32) -> Vec { cisla.iter().map(|c| f(*c)).collect() } fn main() { let cisla = vec![1, -2, 3, -4, 5]; // a) let a = aplikuj_na_vsetky(&cisla, |x| x * 2); // b) let b = aplikuj_na_vsetky(&cisla, |x| x + 100); // c) fn absolutna(x: i32) -> i32 { x.abs() } let c = aplikuj_na_vsetky(&cisla, absolutna); } ``` ## E-4 ```rust fn main() { let mut zoznam = Vec::new(); let mut pridaj = |s: &str| zoznam.push(s.to_string()); pridaj("ahoj"); pridaj("svet"); pridaj("rust"); println!("{:?}", zoznam); // ["ahoj", "svet", "rust"] } ``` ## F-1 ```rust fn pocitaj_znaky(text: &str) -> HashMap { let mut mapa = HashMap::new(); for c in text.chars() { *mapa.entry(c).or_insert(0) += 1; } mapa } ``` ## F-2 ```rust struct Student { meno: String, trieda: String, priemer: f32 } // a) fn pocet_v_triedach(studenti: &[Student]) -> HashMap { let mut mapa = HashMap::new(); for s in studenti { *mapa.entry(s.trieda.clone()).or_insert(0) += 1; } mapa } // b) fn najlepsi_v_triede<'a>(studenti: &'a [Student]) -> HashMap { let mut mapa: HashMap = HashMap::new(); for s in studenti { mapa.entry(s.trieda.clone()) .and_modify(|najlepsi| { if s.priemer < najlepsi.priemer { *najlepsi = s; } }) .or_insert(s); } mapa } ``` ## F-3 ```rust fn invertuj_mapu(mapa: &HashMap) -> HashMap { let mut nova = HashMap::new(); for (k, v) in mapa { nova.insert(v.clone(), k.clone()); } nova } ``` ## G-1 ```rust fn zdvojnasob_option(x: Option) -> Option { x.map(|n| n * 2) } ``` ## G-2 ```rust fn parsuj_prvy_znak(text: Option) -> Option { text.and_then(|t| t.chars().next()) } ``` ## G-3 ```rust fn bezpecne_delenie(a: f64, b: f64) -> Option { Some(b).filter(|b| *b != 0.0).map(|b| a / b) } fn delenie_s_fallbackom(a: f64, b: f64) -> f64 { bezpecne_delenie(a, b).unwrap_or(0.0) } ``` ## G-4 ```rust fn email_pre_id(id: u32) -> Option { najdi_pouzivatela(id).and_then(|meno| najdi_email(&meno)) } ``` ## G-5 ``` Some(true) // map: 5 > 3 = true, zabalí do Some Some(5) // filter: 5 > 3 je true, nechá Some(5) None // filter: 5 > 10 je false, vráti None Some("5") // map: 5.to_string() = "5" Some(10) // and_then: 5 > 3, tak Some(5 * 2) = Some(10) ``` ## H-1 ```rust use serde::{Serialize, Deserialize}; use std::collections::HashMap; #[derive(Serialize, Deserialize, Clone)] struct Produkt { nazov: String, cena: f64, kategoria: String, na_sklade: bool, } #[derive(Serialize, Deserialize, Default)] struct Obchod { produkty: Vec, } impl Obchod { fn nacitaj_zo_suboru(cesta: &std::path::PathBuf) -> Option { let raw = std::fs::read_to_string(cesta).ok()?; serde_json::from_str(&raw).ok() } fn uloz_do_suboru(&self, cesta: &std::path::PathBuf) -> bool { let Ok(json) = serde_json::to_string_pretty(&self) else { return false; }; std::fs::write(cesta, json).is_ok() } fn pridaj(&mut self, produkt: Produkt) -> Result<(), ()> { if self.produkty.iter().any(|p| p.nazov == produkt.nazov) { return Err(()); } self.produkty.push(produkt); Ok(()) } fn odstran(&mut self, nazov: &str) -> Result { let pos = self.produkty.iter().position(|p| p.nazov == nazov).ok_or(())?; Ok(self.produkty.remove(pos)) } fn najdi(&self, nazov: &str) -> Option<&Produkt> { self.produkty.iter().find(|p| p.nazov == nazov) } fn na_sklade(&self) -> Vec<&Produkt> { self.produkty.iter().filter(|p| p.na_sklade).collect() } fn v_kategorii(&self, kat: &str) -> Vec<&Produkt> { self.produkty.iter().filter(|p| p.kategoria == kat).collect() } fn najdrahsi(&self) -> Option<&Produkt> { self.produkty.iter().max_by(|a, b| a.cena.partial_cmp(&b.cena).unwrap()) } fn priemerna_cena_v_kategorii(&self, kat: &str) -> Option { let v_kat: Vec<&Produkt> = self.v_kategorii(kat); if v_kat.is_empty() { return None; } let sucet: f64 = v_kat.iter().map(|p| p.cena).sum(); Some(sucet / v_kat.len() as f64) } fn pocty_kategorii(&self) -> HashMap { let mut mapa = HashMap::new(); for p in &self.produkty { *mapa.entry(p.kategoria.clone()).or_insert(0) += 1; } mapa } } ``` ## H-2 ```rust use std::fmt; enum Velkost { Mala, Stredna, Velka } impl fmt::Display for Velkost { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self { Velkost::Mala => write!(f, "S"), Velkost::Stredna => write!(f, "M"), Velkost::Velka => write!(f, "L"), } } } struct Tricko { farba: String, velkost: Velkost, cena: f64 } impl fmt::Display for Tricko { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "Tričko [{}] {} - {:.2}€", self.velkost, self.farba, self.cena) } } ```