diff --git a/priprava/rust_priprava14.md b/priprava/rust_priprava14.md index f666cb9..62ff570 100644 --- a/priprava/rust_priprava14.md +++ b/priprava/rust_priprava14.md @@ -1,114 +1,110 @@ -# rand — krok za krokom +# rand — krok za krokom (aktuálna verzia) Každá kapitola: prečítaj, pozri príklady, urob úlohy. Až potom choď ďalej. `Cargo.toml`: ```toml [dependencies] -rand = "0.8" +rand = "0.10" ``` +Najjednoduchší import — dáva ti všetko bežné: ```rust -use rand::Rng; // toto treba skoro vždy +use rand::prelude::*; ``` --- -## Kapitola 1: Generátor náhodných čísel — thread_rng - -Všetko začína generátorom. V Ruste sa volá `thread_rng()`: +## Kapitola 1: Generátor — rand::rng() ```rust use rand::Rng; fn main() { - // Vytvor generátor - let mut rng = rand::thread_rng(); + let mut rng = rand::rng(); - // Náhodné i32 (celý rozsah) - let cislo: i32 = rng.gen(); - println!("{}", cislo); // napr. -1847294628 + // Náhodné celé číslo (celý rozsah typu) + let cislo: i32 = rng.random(); + println!("{}", cislo); // Náhodné f64 medzi 0.0 a 1.0 - let desatinne: f64 = rng.gen(); - println!("{}", desatinne); // napr. 0.7382... + let desatinne: f64 = rng.random(); + println!("{}", desatinne); // Náhodné bool - let minca: bool = rng.gen(); - println!("{}", minca); // true alebo false + let minca: bool = rng.random(); + println!("{}", minca); } ``` -**`mut rng`** — generátor sa mení pri každom volaní (posúva sa jeho vnútorný stav), preto musí byť `mut`. +`mut rng` — generátor mení svoj stav pri každom volaní. ### Úlohy 1 **1a.** Vygeneruj 5 náhodných i32 čísel. Vypíš ich. -**1b.** Vygeneruj 10 náhodných bool hodnôt. Spočítaj koľko bolo true a koľko false. +**1b.** Vygeneruj 10 náhodných bool hodnôt. Spočítaj koľko bolo true. **1c.** Čo je zle? ```rust -let rng = rand::thread_rng(); -let cislo: i32 = rng.gen(); +let rng = rand::rng(); +let cislo: i32 = rng.random(); ``` --- -## Kapitola 2: gen_range — číslo v rozsahu +## Kapitola 2: random_range — číslo v rozsahu ```rust use rand::Rng; -let mut rng = rand::thread_rng(); +let mut rng = rand::rng(); -// Celé číslo od 1 do 10 (vrátane oboch) -let cislo: i32 = rng.gen_range(1..=10); +// Od 1 do 10 (vrátane oboch) +let cislo: i32 = rng.random_range(1..=10); -// Celé číslo od 1 do 9 (10 NIE JE zahrnuté) -let cislo: i32 = rng.gen_range(1..10); +// Od 1 do 9 (10 NIE JE zahrnuté) +let cislo: i32 = rng.random_range(1..10); // Float od 0.0 do 1.0 (1.0 nie je zahrnuté) -let cislo: f64 = rng.gen_range(0.0..1.0); +let cislo: f64 = rng.random_range(0.0..1.0); -// Index do vektora +// Náhodný index do vektora let vektor = vec!["a", "b", "c", "d", "e"]; -let index: usize = rng.gen_range(0..vektor.len()); +let index: usize = rng.random_range(0..vektor.len()); let nahodny_prvok = &vektor[index]; ``` -**`..=`** — inclusive (vrátane konca). `..` — exclusive (bez konca). - | Zápis | Rozsah | Príklad | |-------|--------|---------| -| `1..10` | 1 až 9 | kocka bez 10 | -| `1..=10` | 1 až 10 | kocka s 10 | +| `1..10` | 1 až 9 | bez konca | +| `1..=10` | 1 až 10 | vrátane konca | | `0..vektor.len()` | 0 až posledný index | náhodný index | ### Úlohy 2 -**2a.** Simuluj hod kockou (1–6). Hoď 100-krát a spočítaj koľkokrát padlo každé číslo (použi HashMap). +**2a.** Simuluj hod kockou (1–6). Hoď 100-krát, spočítaj výskyty každého čísla (HashMap). -**2b.** Vygeneruj náhodné heslo — 8 náhodných znakov z abecedy a-z. Hint: vygeneruj číslo 0..26, pripočítaj k `b'a'`, preveď na char. +**2b.** Vygeneruj náhodné heslo — 8 znakov a-z. Hint: `rng.random_range(b'a'..=b'z') as char`. -**2c.** Napíš funkciu `nahodne_cislo_v_rozsahu(od: i32, do_: i32) -> i32`. Použi `gen_range`. +**2c.** Napíš funkciu `nahodne_cislo(od: i32, do_: i32) -> i32`. --- ## Kapitola 3: choose — náhodný výber z kolekcie -Toto je **najdôležitejšie** na skúške. `choose` vyberie náhodný prvok z vektora alebo slice. +Toto je **najdôležitejšie** na skúške. ```rust -use rand::seq::SliceRandom; // TOTO TREBA IMPORTOVAŤ! +use rand::seq::IndexedRandom; // TOTO TREBA! -let mut rng = rand::thread_rng(); +let mut rng = rand::rng(); let ovocie = vec!["jablko", "hruška", "banán", "pomaranč"]; -// choose — vráti Option<&&str> (Option lebo Vec môže byť prázdny) +// choose — vráti Option (None ak prázdny Vec) let nahodne = ovocie.choose(&mut rng); -// Some(&"hruška") — náhodný prvok +// Some(&"hruška") match nahodne { Some(o) => println!("Vybrané: {}", o), @@ -116,43 +112,26 @@ match nahodne { } ``` -**Import:** `use rand::seq::SliceRandom;` — bez tohto `choose` nefunguje! +**Import:** `use rand::seq::IndexedRandom;` — bez tohto `choose` nefunguje! + +Alebo použi `use rand::prelude::*;` — ten to zahŕňa. ### choose s Vec ```rust -use rand::seq::SliceRandom; +use rand::seq::IndexedRandom; let slova = vec!["pes".to_string(), "mačka".to_string(), "kôň".to_string()]; -let mut rng = rand::thread_rng(); +let mut rng = rand::rng(); let nahodne: Option<&String> = slova.choose(&mut rng); // Some(&"mačka") ``` -### choose s Vec - -```rust -struct Otazka { - text: String, - odpoved: String, -} - -let otazky = vec![ - Otazka { text: "2+2?".into(), odpoved: "4".into() }, - Otazka { text: "Hlavné mesto SR?".into(), odpoved: "Bratislava".into() }, -]; - -let nahodna: Option<&Otazka> = otazky.choose(&mut rng); -if let Some(otazka) = nahodna { - println!("{}", otazka.text); -} -``` - ### choose na skúške — SpravcaHry.vytvor_novu_hru ```rust -use rand::seq::SliceRandom; +use rand::seq::IndexedRandom; use std::collections::HashMap; struct SpravcaHry { @@ -161,19 +140,19 @@ struct SpravcaHry { impl SpravcaHry { fn vytvor_novu_hru(&self, kategoria: &str) -> Option { - // 1. Nájdi kategóriu v slovníku + // 1. Nájdi kategóriu let slova = self.slovnik.get(kategoria)?; - // 2. Skontroluj či nie je prázdna + // 2. Prázdna → None if slova.is_empty() { return None; } // 3. Vyber náhodné slovo - let mut rng = rand::thread_rng(); + let mut rng = rand::rng(); let slovo = slova.choose(&mut rng)?; - // 4. Vytvor hru s tým slovom + // 4. Vytvor hru Some(Hra::new(slovo)) } } @@ -181,50 +160,47 @@ impl SpravcaHry { Krok po kroku: ``` -slovnik = {"zvierata": ["pes", "mačka", "kôň"], "jedlo": ["pizza", "burger"]} +slovnik = {"zvierata": ["pes", "mačka", "kôň"]} kategoria = "zvierata" → slovnik.get("zvierata") → Some(&["pes", "mačka", "kôň"]) - → slova = &["pes", "mačka", "kôň"] → slova.choose(&mut rng) → Some(&"mačka") → Hra::new("mačka") - → Some(Hra { hladane_slovo: "mačka", ... }) kategoria = "neexistuje" → slovnik.get("neexistuje") → None - → ? vráti None z funkcie + → ? → return None ``` ### Úlohy 3 -**3a.** Máš Vec mien. Vyber náhodné meno a vypíš ho. +**3a.** Máš Vec mien. Vyber náhodné a vypíš. **3b.** Máš HashMap> (kategória → slová). Napíš funkciu: ```rust fn nahodne_slovo(slovnik: &HashMap>, kategoria: &str) -> Option<&String> ``` -**3c.** Máš Vec. Vyber 5 náhodných otázok (bez opakovania). Hint: pozri kapitolu 5 (shuffle). - -**3d.** Čo sa stane ak zavoláš `.choose()` na prázdnom vektore? +**3c.** Čo sa stane ak zavoláš `.choose()` na prázdnom vektore? --- -## Kapitola 4: choose_multiple — viac náhodných prvkov +## Kapitola 4: sample — viac náhodných prvkov + +V novej verzii rand sa `choose_multiple` nahradil metódou `sample`: ```rust -use rand::seq::SliceRandom; +use rand::seq::IndexedRandom; let cisla = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; -let mut rng = rand::thread_rng(); +let mut rng = rand::rng(); // Vyber 3 náhodné prvky (BEZ opakovania) -let vybrane: Vec<&i32> = cisla.choose_multiple(&mut rng, 3).collect(); +let vybrane: Vec<&i32> = cisla.sample(&mut rng, 3).collect(); // napr. [&7, &2, &9] -// Ak chceš viac ako je prvkov, vráti všetky (v náhodnom poradí) -let vsetky: Vec<&i32> = cisla.choose_multiple(&mut rng, 100).collect(); -// všetkých 10 prvkov v náhodnom poradí +// Ak chceš viac ako je prvkov, vráti len toľko koľko je +let vsetky: Vec<&i32> = cisla.sample(&mut rng, 100).collect(); ``` ### Na skúške — výber N otázok @@ -236,8 +212,8 @@ struct Kviz { impl Kviz { fn nahodnych_n(&self, n: usize) -> Vec<&Otazka> { - let mut rng = rand::thread_rng(); - self.otazky.choose_multiple(&mut rng, n).collect() + let mut rng = rand::rng(); + self.otazky.sample(&mut rng, n).collect() } } ``` @@ -246,89 +222,77 @@ impl Kviz { **4a.** Máš 20 študentov. Vyber 5 náhodných na skúšanie. -**4b.** Máš balíček kariet (Vec). Rozdaj 7 kariet — vyber 7 náhodných. +**4b.** Máš balíček kariet (Vec). Rozdaj 7 kariet. --- ## Kapitola 5: shuffle — zamiešanie ```rust -use rand::seq::SliceRandom; +use rand::seq::SliceRandom; // shuffle je v SliceRandom! let mut cisla = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; -let mut rng = rand::thread_rng(); +let mut rng = rand::rng(); // shuffle — zamieša NA MIESTE (mení Vec) cisla.shuffle(&mut rng); -// cisla je teraz napr. [7, 2, 9, 1, 5, 3, 10, 4, 8, 6] +// napr. [7, 2, 9, 1, 5, 3, 10, 4, 8, 6] ``` -**`&mut self`** — shuffle mení vektor, preto `let mut cisla` a `&mut rng`. +**Import:** `use rand::seq::SliceRandom;` — shuffle je v SliceRandom, nie IndexedRandom! -### Kedy shuffle vs choose_multiple +### Kedy čo -| Chcem... | Použi | -|----------|-------| -| 1 náhodný prvok | `choose` | -| N náhodných (bez zmeny originálu) | `choose_multiple` | -| Zamiešať celý zoznam | `shuffle` | -| Prvých N po zamiešaní | `shuffle` + `.iter().take(n)` | +| Chcem... | Použi | Import | +|----------|-------|--------| +| 1 náhodný prvok | `.choose()` | `IndexedRandom` | +| N náhodných (bez zmeny originálu) | `.sample()` | `IndexedRandom` | +| Zamiešať celý zoznam | `.shuffle()` | `SliceRandom` | -### Na skúške — zamiešanie otázok/odpovedí +### Na skúške — zamiešanie otázok ```rust +use rand::seq::SliceRandom; + impl Kviz { fn hraj(&mut self) { - let mut rng = rand::thread_rng(); - - // Zamieša poradie otázok + let mut rng = rand::rng(); self.otazky.shuffle(&mut rng); for otazka in &self.otazky { println!("{}", otazka.text); - // ... } } } - -// Alebo zamiešaj odpovede ku každej otázke -impl Otazka { - fn zamiesaj_odpovede(&mut self) { - let mut rng = rand::thread_rng(); - self.odpovede.shuffle(&mut rng); - } -} ``` ### Úlohy 5 -**5a.** Máš vektor kariet. Zamieša ho. Vypíš prvých 5 (to je "ruka" hráča). +**5a.** Máš vektor kariet. Zamiešaj. Vypíš prvých 5. -**5b.** Máš Vec. Zamieša poradie. Vypíš otázky v novom poradí. - -**5c.** Čo je zle? +**5b.** Čo je zle? ```rust let cisla = vec![1, 2, 3, 4, 5]; -cisla.shuffle(&mut rand::thread_rng()); +cisla.shuffle(&mut rand::rng()); ``` --- -## Kapitola 6: Generovanie náhodných znakov a reťazcov +## Kapitola 6: Náhodné znaky a reťazce ```rust use rand::Rng; -use rand::distributions::Alphanumeric; +use rand::distr::Alphanumeric; // distr, nie distributions! -let mut rng = rand::thread_rng(); +let mut rng = rand::rng(); // Náhodný ASCII znak a-z -let znak: char = rng.gen_range(b'a'..=b'z') as char; +let znak: char = rng.random_range(b'a'..=b'z') as char; // Náhodný veľký znak A-Z -let znak: char = rng.gen_range(b'A'..=b'Z') as char; +let znak: char = rng.random_range(b'A'..=b'Z') as char; -// Náhodný alfanumerický reťazec (a-z, A-Z, 0-9) +// Alfanumerický reťazec (a-z, A-Z, 0-9) let heslo: String = (0..12) .map(|_| rng.sample(Alphanumeric) as char) .collect(); @@ -338,10 +302,10 @@ let heslo: String = (0..12) ### Výber náhodného znaku z reťazca ```rust -use rand::seq::SliceRandom; +use rand::seq::IndexedRandom; let abeceda: Vec = "abcdefghijklmnopqrstuvwxyz".chars().collect(); -let mut rng = rand::thread_rng(); +let mut rng = rand::rng(); let nahodny_znak = abeceda.choose(&mut rng); // Some(&'m') @@ -349,60 +313,34 @@ let nahodny_znak = abeceda.choose(&mut rng); ### Úlohy 6 -**6a.** Vygeneruj náhodné heslo dlhé 10 znakov, len z malých písmen a-z. +**6a.** Vygeneruj heslo: 10 znakov, len malé písmená a-z. -**6b.** Vygeneruj náhodné meno: veľké prvé písmeno + 4 malé písmená. - -**6c.** Máš abecedu slovenských znakov (vrátane diakritiky) ako Vec. Vyber 5 náhodných. +**6b.** Vygeneruj náhodné meno: veľké prvé + 4 malé písmená. --- -## Kapitola 7: gen_bool a bernoulli — pravdepodobnosť +## Kapitola 7: random_bool — pravdepodobnosť ```rust use rand::Rng; -let mut rng = rand::thread_rng(); +let mut rng = rand::rng(); // 50% šanca na true -let minca: bool = rng.gen_bool(0.5); +let minca: bool = rng.random_bool(0.5); // 70% šanca na true -let dost_casto: bool = rng.gen_bool(0.7); +let dost_casto: bool = rng.random_bool(0.7); // 10% šanca na true -let zriedka: bool = rng.gen_bool(0.1); - -// 100% true -let vzdy: bool = rng.gen_bool(1.0); - -// 0% true -let nikdy: bool = rng.gen_bool(0.0); -``` - -### Praktické použitie - -```rust -// Šanca na kritický zásah v hre -fn je_kriticky_zasah(sila: f64) -> bool { - let mut rng = rand::thread_rng(); - rng.gen_bool(sila / 100.0) // sila 25 → 25% šanca -} - -// Náhodná udalosť -fn nahodna_udalost() { - let mut rng = rand::thread_rng(); - if rng.gen_bool(0.3) { - println!("Nastala špeciálna udalosť! (30% šanca)"); - } -} +let zriedka: bool = rng.random_bool(0.1); ``` ### Úlohy 7 **7a.** Simuluj 1000 hodov mincou. Koľkokrát padol orol (true)? -**7b.** Napíš funkciu, ktorá vráti "Výhra!" s pravdepodobnosťou 15% a "Skús znova" inak. +**7b.** Funkcia vráti "Výhra!" s 15% pravdepodobnosťou, inak "Skús znova". --- @@ -423,8 +361,8 @@ fn prompt(text: &str) -> String { } fn main() { - let mut rng = rand::thread_rng(); - let tajne: i32 = rng.gen_range(1..=100); + let mut rng = rand::rng(); + let tajne: i32 = rng.random_range(1..=100); let mut pokusy = 0; println!("Hádaj číslo od 1 do 100!"); @@ -456,7 +394,7 @@ fn main() { ### Obesenec s náhodným slovom ```rust -use rand::seq::SliceRandom; +use rand::seq::IndexedRandom; use std::collections::{HashSet, HashMap}; use std::io::{self, Write}; @@ -469,14 +407,13 @@ fn nacitaj_znak() -> Option { } fn main() { - // Slovník let slovnik: HashMap<&str, Vec<&str>> = HashMap::from([ ("zvierata", vec!["pes", "macka", "kon", "krava", "zajac"]), ("jedlo", vec!["pizza", "burger", "salat", "rizoto"]), ]); // Vyber náhodnú kategóriu a slovo - let mut rng = rand::thread_rng(); + let mut rng = rand::rng(); let kategorie: Vec<&&str> = slovnik.keys().collect(); let kategoria = **kategorie.choose(&mut rng).unwrap(); let slova = &slovnik[kategoria]; @@ -484,37 +421,32 @@ fn main() { println!("Kategória: {}", kategoria); - // Stav hry let mut uhadnute: HashSet = HashSet::new(); let mut skusane: HashSet = HashSet::new(); let mut zivoty: u8 = 6; loop { - // Zobraz slovo let zobrazene: String = slovo.chars().map(|c| { if uhadnute.contains(&c) { c } else { '_' } }).collect(); println!("\n{} (životov: {})", zobrazene, zivoty); - // Výhra? if slovo.chars().all(|c| uhadnute.contains(&c)) { println!("Vyhral si! Slovo bolo: {}", slovo); break; } - // Prehra? if zivoty == 0 { println!("Prehral si! Slovo bolo: {}", slovo); break; } - // Vstup let Some(pismeno) = nacitaj_znak() else { println!("Neplatný vstup"); continue; }; if !skusane.insert(pismeno) { - println!("Toto písmeno si už skúšal!"); + println!("Už si skúšal!"); continue; } @@ -531,29 +463,25 @@ fn main() { ### Úlohy 8 -**8a.** Napíš hru "hádaj číslo" kde rozsah závisí od obtiažnosti: -- Ľahká: 1–10 -- Stredná: 1–50 -- Ťažká: 1–100 -Použi prompt na výber obtiažnosti. +**8a.** Napíš "hádaj číslo" s obtiažnosťou: ľahká (1–10), stredná (1–50), ťažká (1–100). -**8b.** Napíš jednoduchú kvízovú hru: 5 otázok z náhodne zamiešaného poolu. Každá otázka má 4 odpovede (zamiešané). Hráč zadáva číslo odpovede. +**8b.** Napíš kvízovú hru: 5 otázok z náhodne zamiešaného poolu, hráč zadáva číslo odpovede. --- -## Kapitola 9: Náhodné s kolekciami +## Kapitola 9: Náhodné z HashMap a HashSet -### Náhodný kľúč z HashMap +Pre iterátory (nie slice) treba `IteratorRandom`: ```rust -use rand::seq::IteratorRandom; // TOTO pre .choose na iterátore! +use rand::seq::IteratorRandom; // pre .choose() na iterátore let mut mapa = HashMap::new(); mapa.insert("a", 1); mapa.insert("b", 2); mapa.insert("c", 3); -let mut rng = rand::thread_rng(); +let mut rng = rand::rng(); // Náhodný kľúč let kluc = mapa.keys().choose(&mut rng); @@ -564,33 +492,30 @@ let par = mapa.iter().choose(&mut rng); // Some((&"a", &1)) ``` -**Import:** `use rand::seq::IteratorRandom;` — toto umožní `.choose()` na akomkoľvek iterátore, nielen na slice. - -### Náhodný prvok z HashSet - ```rust +// HashSet — rovnako use rand::seq::IteratorRandom; let mnozina: HashSet = vec!["pes", "mačka", "kôň"] .into_iter().map(String::from).collect(); -let mut rng = rand::thread_rng(); +let mut rng = rand::rng(); let nahodny = mnozina.iter().choose(&mut rng); // Some(&"mačka") ``` ### Úlohy 9 -**9a.** Máš HashMap kategórií. Vyber náhodnú kategóriu (kľúč), potom náhodné slovo z nej. +**9a.** Máš HashMap kategórií. Vyber náhodnú kategóriu, potom náhodné slovo z nej. -**9b.** Máš HashSet skúšaných písmen. Vyber náhodné písmeno z abecedy, ktoré ešte NIE JE v sete. +**9b.** Máš HashSet skúšaných písmen. Vyber písmeno z abecedy, ktoré ešte NIE JE v sete. --- ## Kapitola 10: Kompletný vzor — SpravcaHry zo skúšky ```rust -use rand::seq::SliceRandom; +use rand::seq::IndexedRandom; use serde::{Serialize, Deserialize}; use std::collections::HashMap; use std::path::PathBuf; @@ -613,21 +538,13 @@ impl SpravcaHry { std::fs::write(cesta, json).is_ok() } - // NAJDÔLEŽITEJŠIA METÓDA — náhodné slovo z kategórie pub fn vytvor_novu_hru(&self, kategoria: &str) -> Option { - // 1. Nájdi kategóriu let slova = self.slovnik.get(kategoria)?; - - // 2. Prázdna kategória → None if slova.is_empty() { return None; } - - // 3. Náhodný výber - let mut rng = rand::thread_rng(); + let mut rng = rand::rng(); let slovo = slova.choose(&mut rng)?; - - // 4. Vytvor hru Some(Hra::new(slovo)) } @@ -718,18 +635,11 @@ fn main() { ### Úlohy 10 -**10a.** Napíš celý SpravcaHry od nuly bez pozerania. Musíš mať: -- `slovnik: HashMap>` -- `nacitaj_zo_suboru`, `uloz_do_suboru` -- `pridaj_kategoriu`, `pridaj_slovo` -- `vytvor_novu_hru` s `choose` +**10a.** Napíš celý SpravcaHry od nuly bez pozerania. -**10b.** Napíš main.rs s clapom bez pozerania. Subcommands: -- `pridaj-kategoriu ` -- `pridaj-slovo ` -- `hraj ` +**10b.** Napíš main.rs s clapom bez pozerania. -**10c.** Rozšír SpravcaHry o metódu `nahodna_kategoria(&self) -> Option<&String>` — vyber náhodnú kategóriu. Použi `IteratorRandom`. +**10c.** Rozšír o metódu `nahodna_kategoria(&self) -> Option<&String>`. Použi `IteratorRandom`. --- @@ -737,13 +647,28 @@ fn main() { | Chcem... | Import | Metóda | |----------|--------|--------| -| Náhodné číslo | `use rand::Rng;` | `rng.gen()`, `rng.gen_range(1..=6)` | -| Náhodný bool | `use rand::Rng;` | `rng.gen_bool(0.5)` | -| Náhodný prvok z Vec/slice | `use rand::seq::SliceRandom;` | `vec.choose(&mut rng)` | -| Viac náhodných prvkov | `use rand::seq::SliceRandom;` | `vec.choose_multiple(&mut rng, n)` | +| Náhodné číslo | `use rand::Rng;` | `rng.random()` | +| Číslo v rozsahu | `use rand::Rng;` | `rng.random_range(1..=6)` | +| Náhodný bool | `use rand::Rng;` | `rng.random_bool(0.5)` | +| Náhodný prvok z Vec | `use rand::seq::IndexedRandom;` | `vec.choose(&mut rng)` | +| N náhodných prvkov | `use rand::seq::IndexedRandom;` | `vec.sample(&mut rng, n)` | | Zamiešať Vec | `use rand::seq::SliceRandom;` | `vec.shuffle(&mut rng)` | -| Náhodný z iterátora (HashMap, HashSet) | `use rand::seq::IteratorRandom;` | `iter.choose(&mut rng)` | -| Alfanumerické znaky | `use rand::distributions::Alphanumeric;` | `rng.sample(Alphanumeric)` | +| Náhodný z iterátora | `use rand::seq::IteratorRandom;` | `iter.choose(&mut rng)` | +| Alfanumerické znaky | `use rand::distr::Alphanumeric;` | `rng.sample(Alphanumeric) as char` | +| Všetko naraz | `use rand::prelude::*;` | zahŕňa Rng, IndexedRandom, SliceRandom | -**Vždy:** `let mut rng = rand::thread_rng();` — vytvor generátor. -**Vždy:** `&mut rng` — predávaj ako meniteľnú referenciu. +**Vždy:** `let mut rng = rand::rng();` + +## Zmeny oproti starým verziám (0.8) + +Ak niekde vidíš starý kód, tu je preklad: + +| Staré (rand 0.8) | Nové (rand 0.9+) | +|-------------------|-------------------| +| `rand::thread_rng()` | `rand::rng()` | +| `rng.gen()` | `rng.random()` | +| `rng.gen_range(1..=6)` | `rng.random_range(1..=6)` | +| `rng.gen_bool(0.5)` | `rng.random_bool(0.5)` | +| `use rand::distributions::` | `use rand::distr::` | +| `vec.choose_multiple(&mut rng, n)` | `vec.sample(&mut rng, n)` | +| `use rand::seq::SliceRandom;` (pre choose) | `use rand::seq::IndexedRandom;` | diff --git a/priprava/rust_priprava15.md b/priprava/rust_priprava15.md new file mode 100644 index 0000000..1e2b3f5 --- /dev/null +++ b/priprava/rust_priprava15.md @@ -0,0 +1,298 @@ +# Ok, ok(), is_ok(), () — rýchlokurz + +--- + +## 1. Dva svety: Result a Option + +``` +Result → Ok(hodnota) alebo Err(chyba) +Option → 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é". + +```rust +// 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á: + +```rust +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: + +```rust +fn pridaj(&mut self, meno: &str) -> Result<(), ()> { ... } +fn nastav(&mut self, hodnota: u32) -> Result<(), ()> { ... } +``` + +### Kedy Result + +Keď pri úspechu vraciaš niečo, ale chyba nemá detail: + +```rust +fn odstran(&mut self, meno: &str) -> Result { ... } +// Ok(kniha) — tu je odstránená kniha +// Err(()) — nenašiel som ju +``` + +### Kedy Result + +Keď chceš popísať chybu: + +```rust +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: + +```rust +Result → .ok() → Option + +Ok(42) → .ok() → Some(42) +Err("chyba") → .ok() → None +``` + +```rust +// Prakticky: +let cislo: Result = "42".parse(); +let cislo: Option = "42".parse().ok(); // Some(42) +let cislo: Option = "abc".parse().ok(); // None + +// Súborový I/O: +let obsah: Result = fs::read_to_string("data.json"); +let obsah: Option = 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: + +```rust +fn nacitaj_zo_suboru(cesta: &PathBuf) -> Option { + let raw = fs::read_to_string(cesta).ok()?; + // ^^^^^^^^^^^^^^^^^^^^^^^^^ Result + // .ok() → Option + // ? → 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 + +```rust +let vysledok: Result = Ok(42); + +vysledok.is_ok() // true +vysledok.is_err() // false + +let vysledok: Result = Err("chyba".into()); + +vysledok.is_ok() // false +vysledok.is_err() // true +``` + +**Hlavné použitie — ukladanie:** + +```rust +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()` dá `bool`. + +--- + +## 7. .ok_or() a .ok_or_else() — Option → Result + +Opačný smer: máš Option, chceš Result. + +```rust +Option → .ok_or(chyba) → Result + +Some(42) → .ok_or("nič") → Ok(42) +None → .ok_or("nič") → Err("nič") +``` + +```rust +// Prakticky — position vracia Option, ty chceš Result +fn odstran(&mut self, meno: &str) -> Result { + let pos = self.mena.iter().position(|m| m == meno).ok_or(())?; + // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Option + // .ok_or(()) → Result + // ? → ak Err, return Err + Ok(self.mena.remove(pos)) +} +``` + +```rust +// 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 + +```rust +// Option +let cislo: Option = None; +cislo.unwrap_or(0) // 0 — fallback +cislo.unwrap_or_default() // 0 — default pre i32 + +// Result +let cislo: Result = "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 + .unwrap_or_default(); // Kniznica::default() ak None +``` + +--- + +## 9. let...else — rozbaľ alebo odíď + +```rust +// 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` | `Ok(hodnota)` | `Err(())` | +| `Result<(), String>` | `Ok(())` | `Err("popis".into())` | +| `Result` | `Ok(hodnota)` | `Err(format!("..."))` | +| `Option` | `Some(hodnota)` | `None` | +| `bool` | `true` | `false` | + +### Konverzie — kompletná mapa + +``` +Result ──.ok()──────→ Option (zahodí E) +Result ──.is_ok()───→ bool +Result ──.is_err()──→ bool + +Option ──.ok_or(e)─────→ Result (pridá E) +Option ──.is_some()────→ bool +Option ──.is_none()────→ bool + +Result ──.unwrap_or(val)────→ T +Option ──.unwrap_or(val)────→ T + +Result ──.unwrap_or_default()──→ T (T: Default) +Option ──.unwrap_or_default()──→ T (T: Default) +```