Compare commits
15 Commits
f8814e7e1a
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
48426abb5c | ||
|
|
edcd19c8c4 | ||
|
|
a00d00070e | ||
|
|
aed169f828 | ||
|
|
508c97cc9c | ||
|
|
c9b1b60ac1 | ||
|
|
8be1423b55 | ||
|
|
3078efd928 | ||
|
|
5182e2f833 | ||
|
|
ce6b9b01d9 | ||
|
|
fac12bc665 | ||
|
|
cea388f9e1 | ||
|
|
d26cd97aa9 | ||
|
|
4b452112e9 | ||
|
|
7fe89b0361 |
16
JR-priprava-na-skusku6/Cargo.lock
generated
16
JR-priprava-na-skusku6/Cargo.lock
generated
@@ -6,10 +6,26 @@ version = 4
|
|||||||
name = "JR-priprava-na-skusku6"
|
name = "JR-priprava-na-skusku6"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"itertools",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "either"
|
||||||
|
version = "1.15.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "itertools"
|
||||||
|
version = "0.14.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "2b192c782037fadd9cfa75548310488aabdbf3d2da73885b31bd0abd03351285"
|
||||||
|
dependencies = [
|
||||||
|
"either",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "itoa"
|
name = "itoa"
|
||||||
version = "1.0.17"
|
version = "1.0.17"
|
||||||
|
|||||||
@@ -4,5 +4,6 @@ version = "0.1.0"
|
|||||||
edition = "2024"
|
edition = "2024"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
itertools = "0.14.0"
|
||||||
serde = { version = "1.0.228", features = ["derive"] }
|
serde = { version = "1.0.228", features = ["derive"] }
|
||||||
serde_json = "1.0.149"
|
serde_json = "1.0.149"
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
pub mod priprava3;
|
||||||
|
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
@@ -78,6 +80,30 @@ impl Filmoteka {
|
|||||||
result
|
result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn nacitaj(cesta: &str) -> Result<String, std::io::Error> {
|
||||||
|
std::fs::read_to_string(cesta)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn nacitaj2(cesta: &str) -> bool {
|
||||||
|
std::fs::read_to_string(cesta).is_ok()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn nacitaj3(cesta: &str) -> Result<String, String> {
|
||||||
|
match std::fs::read_to_string(cesta) {
|
||||||
|
Ok(obsah) => Ok(obsah),
|
||||||
|
Err(err) => Err(err.to_string()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parsuj_cislo(text: &str) -> Option<i32> {
|
||||||
|
let x = text.parse::<i32>();
|
||||||
|
x.ok()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parsuj_cislo2(text: &str) -> Option<i32> {
|
||||||
|
text.parse::<i32>().ok()
|
||||||
|
}
|
||||||
|
|
||||||
pub fn uloz_do_suboru(&self, cesta: &std::path::PathBuf) -> bool {
|
pub fn uloz_do_suboru(&self, cesta: &std::path::PathBuf) -> bool {
|
||||||
let Ok(json) = serde_json::to_string_pretty(&self) else {
|
let Ok(json) = serde_json::to_string_pretty(&self) else {
|
||||||
return false;
|
return false;
|
||||||
@@ -86,3 +112,22 @@ impl Filmoteka {
|
|||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Film {
|
||||||
|
pub fn new(
|
||||||
|
nazov: &str,
|
||||||
|
reziser: &str,
|
||||||
|
rok: u16,
|
||||||
|
zaner: Zaner,
|
||||||
|
hodnotenie: f32
|
||||||
|
) -> Option<Self> {
|
||||||
|
if hodnotenie < 0.0 || hodnotenie > 10.0 {
|
||||||
|
return None;
|
||||||
|
};
|
||||||
|
return Some(Self {
|
||||||
|
nazov: nazov.to_string(),
|
||||||
|
reziser: reziser.to_string(),
|
||||||
|
rok, zaner, hodnotenie
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,5 +1,22 @@
|
|||||||
|
use std::collections::BTreeMap;
|
||||||
|
use itertools::Itertools;
|
||||||
|
use std::cmp::Reverse;
|
||||||
|
use std::collections::HashSet;
|
||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
println!("Hello, world!");
|
// priprava3::spusti();
|
||||||
|
|
||||||
|
let input = vec![1, 3, 2, 1, 2, 3, 1, 1, 2];
|
||||||
|
let sorted = input.iter().sorted().collect::<Vec<_>>();
|
||||||
|
let mut vys: HashMap<i32, usize> = HashMap::new();
|
||||||
|
for (i, j) in &sorted.into_iter().chunk_by(|&x| x) {
|
||||||
|
// vys.insert(i, j);
|
||||||
|
print!("{:#?}", i);
|
||||||
|
let r = j.cloned().collect::<Vec<_>>();
|
||||||
|
vys.insert(*i, r.len());
|
||||||
|
print!("{:#?}", r);
|
||||||
|
}
|
||||||
|
|
||||||
|
println!("{:#?}", vys)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
75
JR-priprava-na-skusku6/src/priprava3.rs
Normal file
75
JR-priprava-na-skusku6/src/priprava3.rs
Normal file
@@ -0,0 +1,75 @@
|
|||||||
|
use std::fmt;
|
||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
|
pub fn spusti() {
|
||||||
|
let z1 = Zamestnanec::new("Meno", "1 oddelenie", 1000);
|
||||||
|
let z2 = Zamestnanec::new("Meno2", "2 oddelenie", 1300);
|
||||||
|
let z3 = Zamestnanec::new("Meno3", "2 oddelenie", 1100);
|
||||||
|
let z: &[Zamestnanec] = &[z1, z2, z3];
|
||||||
|
// celkovy_plat_na_oddeleni(z);
|
||||||
|
// pocet_na_oddeleni(z);
|
||||||
|
// vypis_statistiky2(z);
|
||||||
|
oddelenie_s_najvyssim_platom(z);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct Zamestnanec { meno: String, oddelenie: String, plat: u32 }
|
||||||
|
|
||||||
|
impl Zamestnanec {
|
||||||
|
pub fn new(meno: &str, oddelenie: &str, plat: u32) -> Self {
|
||||||
|
Self {
|
||||||
|
meno: meno.to_string(),
|
||||||
|
oddelenie: oddelenie.to_string(),
|
||||||
|
plat
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn pocet_na_oddeleni(zamestnanci: &[Zamestnanec]) -> HashMap<String, usize> {
|
||||||
|
let mut mapa: HashMap<String, usize> = HashMap::new();
|
||||||
|
// mapa.entry(zamestnanci).and_modify(|counter| *counter += 1).or_insert(1);
|
||||||
|
// println!("{:#?}", zamestnanci);
|
||||||
|
for x in zamestnanci {
|
||||||
|
mapa.entry(x.oddelenie.clone()).and_modify(|counter| *counter += 1).or_insert(1);
|
||||||
|
}
|
||||||
|
// println!("{:#?}", mapa);
|
||||||
|
mapa
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn celkovy_plat_na_oddeleni(zamestnanci: &[Zamestnanec]) -> HashMap<String, u32> {
|
||||||
|
let mut mapa: HashMap<String, u32> = HashMap::new();
|
||||||
|
for x in zamestnanci {
|
||||||
|
mapa.entry(x.oddelenie.clone()).and_modify(|c| *c += x.plat).or_insert(x.plat);
|
||||||
|
}
|
||||||
|
// println!("{:#?}", mapa);
|
||||||
|
mapa
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn vypis_statistiky(zamestnanci: &[Zamestnanec]) {
|
||||||
|
let mut mapa: HashMap<String, (usize, u32)> = HashMap::new();
|
||||||
|
for x in zamestnanci {
|
||||||
|
mapa.entry(x.oddelenie.clone()).and_modify(|(count, total)| {
|
||||||
|
*count += 1;
|
||||||
|
*total += x.plat;
|
||||||
|
}).or_insert((1, x.plat));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn vypis_statistiky2(zamestnanci: &[Zamestnanec]) {
|
||||||
|
let pocet = pocet_na_oddeleni(zamestnanci);
|
||||||
|
let plat = celkovy_plat_na_oddeleni(zamestnanci);
|
||||||
|
for oddelenie in pocet.keys() {
|
||||||
|
println!("Pocet ludi:{:#?}, a ich plat: {:#?}", *pocet.get(oddelenie).unwrap_or(&0), *plat.get(oddelenie).unwrap_or(&0));
|
||||||
|
}
|
||||||
|
println!("{:#?}, {:#?}", pocet, plat);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn oddelenie_s_najvyssim_platom(zamestnanci: &[Zamestnanec]) -> Option<String> {
|
||||||
|
let plat = celkovy_plat_na_oddeleni(zamestnanci);
|
||||||
|
let max = plat.iter().max_by_key(|x| *x);
|
||||||
|
println!("{:#?}", max);
|
||||||
|
match max {
|
||||||
|
Some(x) => return Some(x.0.clone()),
|
||||||
|
None => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
956
priprava/rust_priprava10.md
Normal file
956
priprava/rust_priprava10.md
Normal file
@@ -0,0 +1,956 @@
|
|||||||
|
# clap — krok za krokom
|
||||||
|
|
||||||
|
Každá kapitola: prečítaj, pozri príklady, urob úlohy. Až potom choď ďalej.
|
||||||
|
|
||||||
|
`Cargo.toml`:
|
||||||
|
```toml
|
||||||
|
[dependencies]
|
||||||
|
clap = { version = "4", features = ["derive"] }
|
||||||
|
```
|
||||||
|
|
||||||
|
```rust
|
||||||
|
use clap::Parser;
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Kapitola 1: Čo je clap
|
||||||
|
|
||||||
|
clap je knižnica na spracovanie **argumentov príkazového riadku** (CLI argumentov).
|
||||||
|
|
||||||
|
Keď spustíš program z terminálu:
|
||||||
|
```bash
|
||||||
|
./moj_program --subor data.json --pocet 5 --verbose
|
||||||
|
```
|
||||||
|
|
||||||
|
clap ti tie argumenty automaticky sparsuje do Rust štruktúry.
|
||||||
|
|
||||||
|
```rust
|
||||||
|
use clap::Parser;
|
||||||
|
|
||||||
|
#[derive(Parser)]
|
||||||
|
struct Argumenty {
|
||||||
|
#[arg(short, long)]
|
||||||
|
subor: String,
|
||||||
|
|
||||||
|
#[arg(short, long)]
|
||||||
|
pocet: u32,
|
||||||
|
|
||||||
|
#[arg(short, long)]
|
||||||
|
verbose: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let args = Argumenty::parse();
|
||||||
|
println!("Súbor: {}", args.subor);
|
||||||
|
println!("Počet: {}", args.pocet);
|
||||||
|
println!("Verbose: {}", args.verbose);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Spustenie:
|
||||||
|
```bash
|
||||||
|
./moj_program --subor data.json --pocet 5 --verbose
|
||||||
|
# Súbor: data.json
|
||||||
|
# Počet: 5
|
||||||
|
# Verbose: true
|
||||||
|
|
||||||
|
./moj_program -s data.json -p 5 -v
|
||||||
|
# To isté — short varianty
|
||||||
|
|
||||||
|
./moj_program --help
|
||||||
|
# Automaticky vygenerovaná nápoveda!
|
||||||
|
```
|
||||||
|
|
||||||
|
**Čo clap robí za teba:**
|
||||||
|
- Parsuje argumenty z príkazového riadku
|
||||||
|
- Validuje typy (ak --pocet nie je číslo → chybová hláška)
|
||||||
|
- Generuje `--help` automaticky
|
||||||
|
- Generuje chybové hlášky ak niečo chýba
|
||||||
|
- Podporuje short (`-s`) aj long (`--subor`) verzie
|
||||||
|
|
||||||
|
### Úlohy 1
|
||||||
|
|
||||||
|
**1a.** Čo je CLI argument? Uveď 3 príklady programov, ktoré berú argumenty (napr. `ls -la`).
|
||||||
|
|
||||||
|
**1b.** Napíš štruktúru `Args` s jedným argumentom `meno: String` (long + short). Sparsuj a vypíš.
|
||||||
|
|
||||||
|
**1c.** Čo sa stane keď spustíš program bez argumentov? Čo keď s `--help`?
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Kapitola 2: Typy argumentov
|
||||||
|
|
||||||
|
### Povinný argument
|
||||||
|
|
||||||
|
```rust
|
||||||
|
#[derive(Parser)]
|
||||||
|
struct Args {
|
||||||
|
#[arg(short, long)]
|
||||||
|
subor: String, // POVINNÝ — program spadne ak chýba
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
```bash
|
||||||
|
./program --subor data.json # OK
|
||||||
|
./program # CHYBA: "required arguments were not provided"
|
||||||
|
```
|
||||||
|
|
||||||
|
### Voliteľný argument (Option)
|
||||||
|
|
||||||
|
```rust
|
||||||
|
#[derive(Parser)]
|
||||||
|
struct Args {
|
||||||
|
#[arg(short, long)]
|
||||||
|
subor: Option<String>, // VOLITEĽNÝ — None ak neuvedený
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
```bash
|
||||||
|
./program --subor data.json # args.subor = Some("data.json")
|
||||||
|
./program # args.subor = None
|
||||||
|
```
|
||||||
|
|
||||||
|
### Bool flag
|
||||||
|
|
||||||
|
```rust
|
||||||
|
#[derive(Parser)]
|
||||||
|
struct Args {
|
||||||
|
#[arg(short, long)]
|
||||||
|
verbose: bool, // false ak neuvedený, true ak uvedený
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
```bash
|
||||||
|
./program --verbose # args.verbose = true
|
||||||
|
./program -v # args.verbose = true
|
||||||
|
./program # args.verbose = false
|
||||||
|
```
|
||||||
|
|
||||||
|
Bool flag neberá hodnotu! Stačí ho uviesť a je true.
|
||||||
|
|
||||||
|
### Argument s default hodnotou
|
||||||
|
|
||||||
|
```rust
|
||||||
|
#[derive(Parser)]
|
||||||
|
struct Args {
|
||||||
|
#[arg(short, long, default_value = "data.json")]
|
||||||
|
subor: String,
|
||||||
|
|
||||||
|
#[arg(short, long, default_value_t = 10)]
|
||||||
|
pocet: u32,
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
```bash
|
||||||
|
./program # subor = "data.json", pocet = 10
|
||||||
|
./program --subor iny.json # subor = "iny.json", pocet = 10
|
||||||
|
./program -p 5 # subor = "data.json", pocet = 5
|
||||||
|
```
|
||||||
|
|
||||||
|
**Pozor:** `default_value` je pre String (vždy v úvodzovkách). `default_value_t` je pre iné typy (čísla, bool).
|
||||||
|
|
||||||
|
### Úlohy 2
|
||||||
|
|
||||||
|
**2a.** Napíš Args s:
|
||||||
|
- `subor: String` — povinný
|
||||||
|
- `vystup: Option<String>` — voliteľný
|
||||||
|
- `pocet: u32` — default 5
|
||||||
|
- `verbose: bool` — flag
|
||||||
|
|
||||||
|
Vyskúšaj rôzne kombinácie spustenia.
|
||||||
|
|
||||||
|
**2b.** Čo sa stane ak zadáš `--pocet ahoj` (nie číslo)?
|
||||||
|
|
||||||
|
**2c.** Čo je rozdiel medzi `Option<String>` a `String` s `default_value`?
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Kapitola 3: short a long
|
||||||
|
|
||||||
|
### Automatické short a long
|
||||||
|
|
||||||
|
```rust
|
||||||
|
#[derive(Parser)]
|
||||||
|
struct Args {
|
||||||
|
#[arg(short, long)]
|
||||||
|
subor: String,
|
||||||
|
// --subor hodnota (long = názov poľa)
|
||||||
|
// -s hodnota (short = prvé písmeno)
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Len long (bez short)
|
||||||
|
|
||||||
|
```rust
|
||||||
|
#[derive(Parser)]
|
||||||
|
struct Args {
|
||||||
|
#[arg(long)]
|
||||||
|
konfig: String,
|
||||||
|
// --konfig hodnota OK
|
||||||
|
// -k hodnota NEFUNGUJE
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Len short (bez long)
|
||||||
|
|
||||||
|
```rust
|
||||||
|
#[derive(Parser)]
|
||||||
|
struct Args {
|
||||||
|
#[arg(short)]
|
||||||
|
verbose: bool,
|
||||||
|
// -v OK
|
||||||
|
// --verbose NEFUNGUJE
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Vlastné short/long
|
||||||
|
|
||||||
|
```rust
|
||||||
|
#[derive(Parser)]
|
||||||
|
struct Args {
|
||||||
|
#[arg(short = 'f', long = "file")]
|
||||||
|
subor: String,
|
||||||
|
// -f hodnota OK
|
||||||
|
// --file hodnota OK
|
||||||
|
// --subor hodnota NEFUNGUJE (premenovali sme)
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Kolízia short písmen
|
||||||
|
|
||||||
|
```rust
|
||||||
|
// PROBLÉM: obe majú short 's'
|
||||||
|
#[derive(Parser)]
|
||||||
|
struct Args {
|
||||||
|
#[arg(short, long)]
|
||||||
|
subor: String, // -s
|
||||||
|
|
||||||
|
#[arg(short, long)]
|
||||||
|
stav: String, // -s KOLÍZIA!
|
||||||
|
}
|
||||||
|
// Riešenie: jedného premenuj
|
||||||
|
#[derive(Parser)]
|
||||||
|
struct Args {
|
||||||
|
#[arg(short, long)]
|
||||||
|
subor: String, // -s
|
||||||
|
|
||||||
|
#[arg(short = 't', long)]
|
||||||
|
stav: String, // -t
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Úlohy 3
|
||||||
|
|
||||||
|
**3a.** Napíš Args kde:
|
||||||
|
- `input` má short `-i` a long `--input`
|
||||||
|
- `output` má short `-o` a long `--output`
|
||||||
|
- `debug` má len short `-d` (žiadny long)
|
||||||
|
- `format` má len long `--format` (žiadny short)
|
||||||
|
|
||||||
|
**3b.** Máš 3 polia: `subor`, `stav`, `slovo`. Všetky začínajú na 's'. Vyrieš kolíziu short písmen.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Kapitola 4: Pozičné argumenty
|
||||||
|
|
||||||
|
Doteraz sme používali pomenované argumenty (`--subor`, `-s`). Existujú aj pozičné — bez mena, len podľa poradia.
|
||||||
|
|
||||||
|
```rust
|
||||||
|
#[derive(Parser)]
|
||||||
|
struct Args {
|
||||||
|
/// Vstupný súbor
|
||||||
|
vstup: String, // PRVÝ pozičný argument
|
||||||
|
|
||||||
|
/// Výstupný súbor
|
||||||
|
vystup: String, // DRUHÝ pozičný argument
|
||||||
|
|
||||||
|
#[arg(short, long)]
|
||||||
|
verbose: bool, // Pomenovaný (flag)
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
```bash
|
||||||
|
./program input.json output.json --verbose
|
||||||
|
# ^^^^^^^^^^ ^^^^^^^^^^^
|
||||||
|
# prvý druhý pozičný
|
||||||
|
```
|
||||||
|
|
||||||
|
**Pravidlo:** Ak pole nemá `#[arg(short, long)]`, je pozičné.
|
||||||
|
|
||||||
|
### Voliteľný pozičný
|
||||||
|
|
||||||
|
```rust
|
||||||
|
#[derive(Parser)]
|
||||||
|
struct Args {
|
||||||
|
vstup: String, // povinný pozičný
|
||||||
|
vystup: Option<String>, // voliteľný pozičný
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
```bash
|
||||||
|
./program input.json # vystup = None
|
||||||
|
./program input.json output.json # vystup = Some("output.json")
|
||||||
|
```
|
||||||
|
|
||||||
|
### Pozičný s default
|
||||||
|
|
||||||
|
```rust
|
||||||
|
#[derive(Parser)]
|
||||||
|
struct Args {
|
||||||
|
#[arg(default_value = "data.json")]
|
||||||
|
subor: String,
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
```bash
|
||||||
|
./program # subor = "data.json"
|
||||||
|
./program iny.json # subor = "iny.json"
|
||||||
|
```
|
||||||
|
|
||||||
|
### Úlohy 4
|
||||||
|
|
||||||
|
**4a.** Napíš Args pre program, ktorý kopíruje súbor:
|
||||||
|
```bash
|
||||||
|
./kopiruj zdrojovy.txt cielovy.txt
|
||||||
|
```
|
||||||
|
Dva pozičné argumenty.
|
||||||
|
|
||||||
|
**4b.** Napíš Args pre grep-like program:
|
||||||
|
```bash
|
||||||
|
./hladaj "hľadaný text" subor.txt --ignore-case
|
||||||
|
```
|
||||||
|
Pozičné: vzor a súbor. Pomenované: ignore_case (bool flag).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Kapitola 5: Popis a help text
|
||||||
|
|
||||||
|
### Dokumentačné komentáre → help text
|
||||||
|
|
||||||
|
```rust
|
||||||
|
/// Správca knižnice — CLI nástroj na správu kníh
|
||||||
|
#[derive(Parser)]
|
||||||
|
struct Args {
|
||||||
|
/// Cesta k JSON súboru s dátami
|
||||||
|
#[arg(short, long)]
|
||||||
|
subor: String,
|
||||||
|
|
||||||
|
/// Počet výsledkov na stránku
|
||||||
|
#[arg(short, long, default_value_t = 10)]
|
||||||
|
pocet: u32,
|
||||||
|
|
||||||
|
/// Zapni podrobný výpis
|
||||||
|
#[arg(short, long)]
|
||||||
|
verbose: bool,
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
```bash
|
||||||
|
./program --help
|
||||||
|
# Správca knižnice — CLI nástroj na správu kníh
|
||||||
|
#
|
||||||
|
# Usage: program [OPTIONS] --subor <SUBOR>
|
||||||
|
#
|
||||||
|
# Options:
|
||||||
|
# -s, --subor <SUBOR> Cesta k JSON súboru s dátami
|
||||||
|
# -p, --pocet <POCET> Počet výsledkov na stránku [default: 10]
|
||||||
|
# -v, --verbose Zapni podrobný výpis
|
||||||
|
# -h, --help Print help
|
||||||
|
```
|
||||||
|
|
||||||
|
**Pravidlo:** `///` komentár nad štruktúrou = popis programu. `///` nad poľom = popis argumentu. clap ich automaticky zobrazí v `--help`.
|
||||||
|
|
||||||
|
### about a help atribúty
|
||||||
|
|
||||||
|
```rust
|
||||||
|
#[derive(Parser)]
|
||||||
|
#[command(about = "Správca knižnice", version = "1.0")]
|
||||||
|
struct Args {
|
||||||
|
#[arg(short, long, help = "Cesta k súboru")]
|
||||||
|
subor: String,
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
```bash
|
||||||
|
./program --version
|
||||||
|
# program 1.0
|
||||||
|
```
|
||||||
|
|
||||||
|
### Úlohy 5
|
||||||
|
|
||||||
|
**5a.** Pridaj ku každému argumentu z úlohy 2a popis (`///` komentár). Spusti s `--help` a pozri výstup.
|
||||||
|
|
||||||
|
**5b.** Pridaj k štruktúre `#[command(about, version)]`. Vyskúšaj `--help` a `--version`.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Kapitola 6: Subcommands — podpríkazy
|
||||||
|
|
||||||
|
Väčšie programy majú podpríkazy:
|
||||||
|
```bash
|
||||||
|
git add file.txt
|
||||||
|
git commit -m "správa"
|
||||||
|
git push origin main
|
||||||
|
```
|
||||||
|
|
||||||
|
V clap to riešiš cez enum:
|
||||||
|
|
||||||
|
```rust
|
||||||
|
use clap::{Parser, Subcommand};
|
||||||
|
|
||||||
|
#[derive(Parser)]
|
||||||
|
struct Args {
|
||||||
|
#[command(subcommand)]
|
||||||
|
prikaz: Prikaz,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Subcommand)]
|
||||||
|
enum Prikaz {
|
||||||
|
/// Pridaj novú knihu
|
||||||
|
Pridaj {
|
||||||
|
/// Názov knihy
|
||||||
|
nazov: String,
|
||||||
|
/// Autor knihy
|
||||||
|
autor: String,
|
||||||
|
},
|
||||||
|
/// Odstráň knihu podľa názvu
|
||||||
|
Odstran {
|
||||||
|
/// Názov knihy na odstránenie
|
||||||
|
nazov: String,
|
||||||
|
},
|
||||||
|
/// Vypíš všetky knihy
|
||||||
|
Vypis,
|
||||||
|
/// Hľadaj knihy
|
||||||
|
Hladaj {
|
||||||
|
/// Hľadaný výraz
|
||||||
|
vyraz: String,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let args = Args::parse();
|
||||||
|
|
||||||
|
match args.prikaz {
|
||||||
|
Prikaz::Pridaj { nazov, autor } => {
|
||||||
|
println!("Pridávam: {} od {}", nazov, autor);
|
||||||
|
}
|
||||||
|
Prikaz::Odstran { nazov } => {
|
||||||
|
println!("Odstraňujem: {}", nazov);
|
||||||
|
}
|
||||||
|
Prikaz::Vypis => {
|
||||||
|
println!("Výpis kníh...");
|
||||||
|
}
|
||||||
|
Prikaz::Hladaj { vyraz } => {
|
||||||
|
println!("Hľadám: {}", vyraz);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
```bash
|
||||||
|
./program pridaj "Duna" "Frank Herbert"
|
||||||
|
./program odstran "Duna"
|
||||||
|
./program vypis
|
||||||
|
./program hladaj "Herbert"
|
||||||
|
./program --help
|
||||||
|
# Shows all subcommands
|
||||||
|
|
||||||
|
./program pridaj --help
|
||||||
|
# Shows help for "pridaj" subcommand
|
||||||
|
```
|
||||||
|
|
||||||
|
### Spoločné argumenty + subcommand
|
||||||
|
|
||||||
|
```rust
|
||||||
|
#[derive(Parser)]
|
||||||
|
struct Args {
|
||||||
|
/// Cesta k JSON súboru
|
||||||
|
#[arg(short, long, default_value = "data.json")]
|
||||||
|
subor: String,
|
||||||
|
|
||||||
|
#[command(subcommand)]
|
||||||
|
prikaz: Prikaz,
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
```bash
|
||||||
|
./program --subor moje.json pridaj "Duna" "Herbert"
|
||||||
|
# ^^^^^^^^^^^^^^^^^ ^^^^^^ spoločný arg pred subcommand
|
||||||
|
```
|
||||||
|
|
||||||
|
### Úlohy 6
|
||||||
|
|
||||||
|
**6a.** Napíš CLI pre správcu kontaktov:
|
||||||
|
```bash
|
||||||
|
./kontakty pridaj "Anna" "+421900000000"
|
||||||
|
./kontakty odstran "Anna"
|
||||||
|
./kontakty vypis
|
||||||
|
./kontakty hladaj "Ann"
|
||||||
|
```
|
||||||
|
|
||||||
|
**6b.** Pridaj spoločný argument `--subor` (default "kontakty.json") pred subcommand.
|
||||||
|
|
||||||
|
**6c.** Pridaj do `pridaj` subcomandu voliteľný argument `--email`.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Kapitola 7: ValueEnum — enum ako argument
|
||||||
|
|
||||||
|
Ak chceš aby argument bol jedna z preddefinovaných hodnôt:
|
||||||
|
|
||||||
|
```rust
|
||||||
|
use clap::{Parser, ValueEnum};
|
||||||
|
|
||||||
|
#[derive(Clone, ValueEnum)]
|
||||||
|
enum Format {
|
||||||
|
Json,
|
||||||
|
Csv,
|
||||||
|
Text,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Parser)]
|
||||||
|
struct Args {
|
||||||
|
#[arg(short, long, default_value = "json")]
|
||||||
|
format: Format,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let args = Args::parse();
|
||||||
|
match args.format {
|
||||||
|
Format::Json => println!("Výstup ako JSON"),
|
||||||
|
Format::Csv => println!("Výstup ako CSV"),
|
||||||
|
Format::Text => println!("Výstup ako text"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
```bash
|
||||||
|
./program --format json
|
||||||
|
./program --format csv
|
||||||
|
./program --format text
|
||||||
|
./program --format xml # CHYBA: "invalid value 'xml'"
|
||||||
|
./program --help
|
||||||
|
# -f, --format <FORMAT> [default: json] [possible values: json, csv, text]
|
||||||
|
```
|
||||||
|
|
||||||
|
clap automaticky:
|
||||||
|
- Ukáže povolené hodnoty v `--help`
|
||||||
|
- Odmietne neplatnú hodnotu
|
||||||
|
- Case-insensitive porovnanie
|
||||||
|
|
||||||
|
### Na skúške — enum Stav ako argument
|
||||||
|
|
||||||
|
```rust
|
||||||
|
#[derive(Clone, ValueEnum, Serialize, Deserialize, PartialEq, Debug)]
|
||||||
|
enum Stav {
|
||||||
|
Nova,
|
||||||
|
Pouzivana,
|
||||||
|
Poskodena,
|
||||||
|
Vyradena,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Subcommand)]
|
||||||
|
enum Prikaz {
|
||||||
|
ZmenStav {
|
||||||
|
nazov: String,
|
||||||
|
#[arg(short, long)]
|
||||||
|
stav: Stav,
|
||||||
|
},
|
||||||
|
PodlaStavu {
|
||||||
|
#[arg(short, long)]
|
||||||
|
stav: Stav,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
```bash
|
||||||
|
./program zmen-stav "Duna" --stav pouzivana
|
||||||
|
./program podla-stavu --stav nova
|
||||||
|
```
|
||||||
|
|
||||||
|
### Úlohy 7
|
||||||
|
|
||||||
|
**7a.** Vytvor enum `Priorita { Nizka, Stredna, Vysoka }` s `ValueEnum`. Použi ho ako argument v CLI.
|
||||||
|
|
||||||
|
**7b.** Pridaj do subcommandu `pridaj` argument `--priorita` typu Priorita s defaultom `Stredna`.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Kapitola 8: Vec argumenty — viacero hodnôt
|
||||||
|
|
||||||
|
```rust
|
||||||
|
#[derive(Parser)]
|
||||||
|
struct Args {
|
||||||
|
/// Súbory na spracovanie
|
||||||
|
subory: Vec<String>, // 0 alebo viac pozičných
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
```bash
|
||||||
|
./program a.txt b.txt c.txt
|
||||||
|
# args.subory = ["a.txt", "b.txt", "c.txt"]
|
||||||
|
|
||||||
|
./program
|
||||||
|
# args.subory = []
|
||||||
|
```
|
||||||
|
|
||||||
|
### Minimálne 1
|
||||||
|
|
||||||
|
```rust
|
||||||
|
#[derive(Parser)]
|
||||||
|
struct Args {
|
||||||
|
/// Súbory na spracovanie (aspoň 1)
|
||||||
|
#[arg(required = true)]
|
||||||
|
subory: Vec<String>,
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
```bash
|
||||||
|
./program a.txt b.txt # OK
|
||||||
|
./program # CHYBA: required
|
||||||
|
```
|
||||||
|
|
||||||
|
### Pomenovaný s viacerými hodnotami
|
||||||
|
|
||||||
|
```rust
|
||||||
|
#[derive(Parser)]
|
||||||
|
struct Args {
|
||||||
|
#[arg(short, long)]
|
||||||
|
tagy: Vec<String>,
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
```bash
|
||||||
|
./program --tagy rust --tagy cli --tagy serde
|
||||||
|
# args.tagy = ["rust", "cli", "serde"]
|
||||||
|
|
||||||
|
./program -t rust -t cli -t serde
|
||||||
|
# to isté
|
||||||
|
```
|
||||||
|
|
||||||
|
### Úlohy 8
|
||||||
|
|
||||||
|
**8a.** Napíš CLI, ktoré berie zoznam čísel a vypočíta ich súčet:
|
||||||
|
```bash
|
||||||
|
./sucet 1 2 3 4 5
|
||||||
|
# Súčet: 15
|
||||||
|
```
|
||||||
|
Hint: pozičný `Vec<i32>`.
|
||||||
|
|
||||||
|
**8b.** Napíš CLI s pomenovaným argumentom `--vyluc` ktorý berie viacero mien. Potom vypíš "Vylúčení: Anna, Boris".
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Kapitola 9: Validácia argumentov
|
||||||
|
|
||||||
|
### value_parser — kontrola rozsahu
|
||||||
|
|
||||||
|
```rust
|
||||||
|
#[derive(Parser)]
|
||||||
|
struct Args {
|
||||||
|
/// Port (1-65535)
|
||||||
|
#[arg(short, long, value_parser = clap::value_parser!(u16).range(1..=65535))]
|
||||||
|
port: u16,
|
||||||
|
|
||||||
|
/// Počet (1-100)
|
||||||
|
#[arg(short, long, value_parser = clap::value_parser!(u32).range(1..=100))]
|
||||||
|
pocet: u32,
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
```bash
|
||||||
|
./program --port 8080 --pocet 50 # OK
|
||||||
|
./program --port 0 # CHYBA: "0 is not in 1..=65535"
|
||||||
|
./program --pocet 200 # CHYBA
|
||||||
|
```
|
||||||
|
|
||||||
|
### PathBuf argument
|
||||||
|
|
||||||
|
Na skúške cesta k súboru je vždy `PathBuf`:
|
||||||
|
|
||||||
|
```rust
|
||||||
|
use std::path::PathBuf;
|
||||||
|
|
||||||
|
#[derive(Parser)]
|
||||||
|
struct Args {
|
||||||
|
/// Cesta k dátovému súboru
|
||||||
|
#[arg(short, long, default_value = "data.json")]
|
||||||
|
subor: PathBuf,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let args = Args::parse();
|
||||||
|
// args.subor je PathBuf — môžeš ho priamo použiť
|
||||||
|
let kniznica = Kniznica::nacitaj_zo_suboru(&args.subor)
|
||||||
|
.unwrap_or_default();
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
```bash
|
||||||
|
./program --subor /cesta/k/suboru.json
|
||||||
|
./program -s data.json
|
||||||
|
./program # default: data.json
|
||||||
|
```
|
||||||
|
|
||||||
|
### Úlohy 9
|
||||||
|
|
||||||
|
**9a.** Napíš Args s argumentom `--vek` typu u8, s rozsahom 0 až 150.
|
||||||
|
|
||||||
|
**9b.** Napíš Args s PathBuf argumentom `--vstup` (povinný) a `--vystup` (voliteľný, default "output.json").
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Kapitola 10: Kompletný vzor zo skúšky
|
||||||
|
|
||||||
|
### Vzor: Knižnica CLI
|
||||||
|
|
||||||
|
```rust
|
||||||
|
use clap::{Parser, Subcommand, ValueEnum};
|
||||||
|
use serde::{Serialize, Deserialize};
|
||||||
|
use std::fs;
|
||||||
|
use std::path::PathBuf;
|
||||||
|
|
||||||
|
// === Typy ===
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, ValueEnum)]
|
||||||
|
pub enum Stav {
|
||||||
|
Nova,
|
||||||
|
Pouzivana,
|
||||||
|
Poskodena,
|
||||||
|
Vyradena,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for Stav {
|
||||||
|
fn default() -> Self {
|
||||||
|
Stav::Nova
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
|
pub struct Kniha {
|
||||||
|
pub nazov: String,
|
||||||
|
pub autor: String,
|
||||||
|
pub rok: u16,
|
||||||
|
pub stav: Stav,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Serialize, Deserialize, Default)]
|
||||||
|
pub struct Kniznica {
|
||||||
|
pub knihy: Vec<Kniha>,
|
||||||
|
}
|
||||||
|
|
||||||
|
// === serde I/O ===
|
||||||
|
|
||||||
|
impl Kniznica {
|
||||||
|
pub fn nacitaj_zo_suboru(cesta: &PathBuf) -> Option<Kniznica> {
|
||||||
|
let raw = fs::read_to_string(cesta).ok()?;
|
||||||
|
serde_json::from_str(&raw).ok()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub 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()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub 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(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn odstran(&mut self, nazov: &str) -> Result<Kniha, String> {
|
||||||
|
let pos = self.knihy.iter()
|
||||||
|
.position(|k| k.nazov == nazov)
|
||||||
|
.ok_or(format!("Kniha '{}' nenájdená", nazov))?;
|
||||||
|
Ok(self.knihy.remove(pos))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// === CLI ===
|
||||||
|
|
||||||
|
/// Správca knižnice
|
||||||
|
#[derive(Parser)]
|
||||||
|
#[command(about, version)]
|
||||||
|
struct Args {
|
||||||
|
/// Cesta k JSON súboru
|
||||||
|
#[arg(short, long, default_value = "kniznica.json")]
|
||||||
|
subor: PathBuf,
|
||||||
|
|
||||||
|
#[command(subcommand)]
|
||||||
|
prikaz: Prikaz,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Subcommand)]
|
||||||
|
enum Prikaz {
|
||||||
|
/// Pridaj novú knihu
|
||||||
|
Pridaj {
|
||||||
|
/// Názov knihy
|
||||||
|
nazov: String,
|
||||||
|
/// Autor knihy
|
||||||
|
autor: String,
|
||||||
|
/// Rok vydania
|
||||||
|
#[arg(short, long)]
|
||||||
|
rok: u16,
|
||||||
|
/// Stav knihy
|
||||||
|
#[arg(short, long, default_value = "nova")]
|
||||||
|
stav: Stav,
|
||||||
|
},
|
||||||
|
/// Odstráň knihu
|
||||||
|
Odstran {
|
||||||
|
/// Názov knihy
|
||||||
|
nazov: String,
|
||||||
|
},
|
||||||
|
/// Vypíš všetky knihy
|
||||||
|
Vypis {
|
||||||
|
/// Filtrovať podľa stavu
|
||||||
|
#[arg(short, long)]
|
||||||
|
stav: Option<Stav>,
|
||||||
|
},
|
||||||
|
/// Hľadaj knihy podľa autora
|
||||||
|
Hladaj {
|
||||||
|
/// Meno autora
|
||||||
|
autor: String,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let args = Args::parse();
|
||||||
|
|
||||||
|
// Načítaj alebo vytvor prázdnu
|
||||||
|
let mut kniznica = Kniznica::nacitaj_zo_suboru(&args.subor)
|
||||||
|
.unwrap_or_default();
|
||||||
|
|
||||||
|
match args.prikaz {
|
||||||
|
Prikaz::Pridaj { nazov, autor, rok, stav } => {
|
||||||
|
let kniha = Kniha { nazov, autor, rok, stav };
|
||||||
|
match kniznica.pridaj(kniha) {
|
||||||
|
Ok(()) => println!("Kniha pridaná."),
|
||||||
|
Err(e) => println!("Chyba: {}", e),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Prikaz::Odstran { nazov } => {
|
||||||
|
match kniznica.odstran(&nazov) {
|
||||||
|
Ok(kniha) => println!("Odstránená: {} ({})", kniha.nazov, kniha.autor),
|
||||||
|
Err(e) => println!("Chyba: {}", e),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Prikaz::Vypis { stav } => {
|
||||||
|
let knihy: Vec<&Kniha> = match &stav {
|
||||||
|
Some(s) => kniznica.knihy.iter().filter(|k| &k.stav == s).collect(),
|
||||||
|
None => kniznica.knihy.iter().collect(),
|
||||||
|
};
|
||||||
|
if knihy.is_empty() {
|
||||||
|
println!("Žiadne knihy.");
|
||||||
|
} else {
|
||||||
|
for kniha in &knihy {
|
||||||
|
println!("{} — {} ({}) [{:?}]", kniha.nazov, kniha.autor, kniha.rok, kniha.stav);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Prikaz::Hladaj { autor } => {
|
||||||
|
let najdene: Vec<&Kniha> = kniznica.knihy.iter()
|
||||||
|
.filter(|k| k.autor.to_lowercase().contains(&autor.to_lowercase()))
|
||||||
|
.collect();
|
||||||
|
if najdene.is_empty() {
|
||||||
|
println!("Nič nenájdené.");
|
||||||
|
} else {
|
||||||
|
for kniha in &najdene {
|
||||||
|
println!("{} — {}", kniha.nazov, kniha.autor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ulož
|
||||||
|
kniznica.uloz_do_suboru(&args.subor);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Spustenie:
|
||||||
|
```bash
|
||||||
|
./kniznica pridaj "Duna" "Frank Herbert" --rok 1965
|
||||||
|
./kniznica pridaj "Hobbit" "J.R.R. Tolkien" --rok 1937 --stav pouzivana
|
||||||
|
./kniznica vypis
|
||||||
|
./kniznica vypis --stav nova
|
||||||
|
./kniznica hladaj "Tolkien"
|
||||||
|
./kniznica odstran "Duna"
|
||||||
|
./kniznica --subor backup.json vypis
|
||||||
|
```
|
||||||
|
|
||||||
|
### Úlohy 10
|
||||||
|
|
||||||
|
**10a.** Implementuj kompletný CLI pre **Správcu úloh** (Task Manager):
|
||||||
|
```
|
||||||
|
Štruktúra: Uloha { nazov: String, priorita: Priorita, hotova: bool }
|
||||||
|
Enum: Priorita { Nizka, Stredna, Vysoka }
|
||||||
|
|
||||||
|
Subcommands:
|
||||||
|
- pridaj <nazov> --priorita <priorita>
|
||||||
|
- hotovo <nazov>
|
||||||
|
- odstran <nazov>
|
||||||
|
- vypis [--priorita <priorita>]
|
||||||
|
- statistiky (počet celkom, hotových, nehotových)
|
||||||
|
|
||||||
|
Spoločný: --subor (PathBuf, default "ulohy.json")
|
||||||
|
```
|
||||||
|
|
||||||
|
**10b.** Implementuj kompletný CLI pre **Milionár** kvíz:
|
||||||
|
```
|
||||||
|
Subcommands:
|
||||||
|
- pridaj-otazku <text> --odpovede <4 odpovede> --spravna <index>
|
||||||
|
- hraj
|
||||||
|
- vypis-otazky
|
||||||
|
|
||||||
|
Spoločný: --subor (PathBuf, default "otazky.json")
|
||||||
|
```
|
||||||
|
|
||||||
|
**10c.** Implementuj kompletný CLI pre **Adresár**:
|
||||||
|
```
|
||||||
|
Štruktúra: Kontakt { meno: String, telefon: String, email: Option<String> }
|
||||||
|
|
||||||
|
Subcommands:
|
||||||
|
- pridaj <meno> <telefon> [--email <email>]
|
||||||
|
- odstran <meno>
|
||||||
|
- hladaj <vyraz>
|
||||||
|
- vypis [--zoradit]
|
||||||
|
- export --format <json|csv>
|
||||||
|
|
||||||
|
Spoločný: --subor (PathBuf, default "kontakty.json")
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Prehľad: clap atribúty
|
||||||
|
|
||||||
|
| Atribút | Kde | Čo robí |
|
||||||
|
|---------|-----|---------|
|
||||||
|
| `#[derive(Parser)]` | štruktúra | Hlavná CLI štruktúra |
|
||||||
|
| `#[derive(Subcommand)]` | enum | Podpríkazy |
|
||||||
|
| `#[derive(ValueEnum)]` | enum | Enum ako hodnota argumentu |
|
||||||
|
| `#[command(subcommand)]` | pole | Toto pole je subcommand |
|
||||||
|
| `#[command(about, version)]` | štruktúra | Pridaj popis a verziu |
|
||||||
|
| `#[arg(short, long)]` | pole | Pomenovaný argument |
|
||||||
|
| `#[arg(short = 'x')]` | pole | Vlastné short písmeno |
|
||||||
|
| `#[arg(long = "nazov")]` | pole | Vlastný long názov |
|
||||||
|
| `#[arg(default_value = "...")]` | pole | Default pre String/PathBuf |
|
||||||
|
| `#[arg(default_value_t = N)]` | pole | Default pre čísla/bool |
|
||||||
|
| `#[arg(required = true)]` | pole | Vynúť aj Vec |
|
||||||
|
| `#[arg(value_parser = ...)]` | pole | Validácia |
|
||||||
|
| `/// komentár` | štruktúra/pole | Help text |
|
||||||
|
|
||||||
|
## Prehľad: typy polí
|
||||||
|
|
||||||
|
| Typ poľa | Správanie |
|
||||||
|
|-----------|-----------|
|
||||||
|
| `String` | Povinný argument |
|
||||||
|
| `Option<String>` | Voliteľný argument |
|
||||||
|
| `bool` | Flag (true/false) |
|
||||||
|
| `Vec<String>` | Viacero hodnôt |
|
||||||
|
| `PathBuf` | Cesta k súboru |
|
||||||
|
| `u32, i32, f64...` | Automaticky parsované |
|
||||||
|
| `MojEnum` (ValueEnum) | Povolené hodnoty |
|
||||||
268
priprava/rust_priprava11.md
Normal file
268
priprava/rust_priprava11.md
Normal file
@@ -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<Kniznica>
|
||||||
|
// 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<Kniha, ()> — 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<Kontakty>
|
||||||
|
// fn uloz_do_suboru(&self, cesta: &PathBuf) -> bool
|
||||||
|
// fn pridaj(&mut self, kontakt: Kontakt) -> Result<(), ()>
|
||||||
|
// fn odstran(&mut self, meno: &str) -> Result<Kontakt, ()>
|
||||||
|
// 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);`
|
||||||
1133
priprava/rust_priprava12.md
Normal file
1133
priprava/rust_priprava12.md
Normal file
File diff suppressed because it is too large
Load Diff
820
priprava/rust_priprava13.md
Normal file
820
priprava/rust_priprava13.md
Normal file
@@ -0,0 +1,820 @@
|
|||||||
|
# I/O v Ruste — krok za krokom
|
||||||
|
|
||||||
|
Každá kapitola: prečítaj, pozri príklady, urob úlohy. Až potom choď ďalej.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Kapitola 1: println! a print! — výstup
|
||||||
|
|
||||||
|
```rust
|
||||||
|
// println! — vypíše + nový riadok
|
||||||
|
println!("Ahoj svet");
|
||||||
|
// Ahoj svet\n
|
||||||
|
|
||||||
|
// print! — vypíše BEZ nového riadku
|
||||||
|
print!("Zadaj meno: ");
|
||||||
|
// Zadaj meno: _ (kurzor zostane na tom istom riadku)
|
||||||
|
```
|
||||||
|
|
||||||
|
### Formátovanie
|
||||||
|
|
||||||
|
```rust
|
||||||
|
let meno = "Anna";
|
||||||
|
let vek = 25;
|
||||||
|
let priemer = 1.847;
|
||||||
|
|
||||||
|
// Základné
|
||||||
|
println!("{} má {} rokov", meno, vek);
|
||||||
|
// Anna má 25 rokov
|
||||||
|
|
||||||
|
// Zaokrúhlenie na 2 desatinné
|
||||||
|
println!("Priemer: {:.2}", priemer);
|
||||||
|
// Priemer: 1.85
|
||||||
|
|
||||||
|
// Zarovnanie
|
||||||
|
println!("{:<10} | {:>5}", "Meno", "Vek");
|
||||||
|
println!("{:<10} | {:>5}", "Anna", 25);
|
||||||
|
println!("{:<10} | {:>5}", "Boris", 30);
|
||||||
|
// Meno | Vek
|
||||||
|
// Anna | 25
|
||||||
|
// Boris | 30
|
||||||
|
|
||||||
|
// Padding znakom
|
||||||
|
println!("{:-^20}", "MENU");
|
||||||
|
// --------MENU--------
|
||||||
|
|
||||||
|
// Debug výpis
|
||||||
|
let vektor = vec![1, 2, 3];
|
||||||
|
println!("{:?}", vektor); // [1, 2, 3]
|
||||||
|
println!("{:#?}", vektor); // pekný formát na viac riadkov
|
||||||
|
```
|
||||||
|
|
||||||
|
### eprintln! — chybový výstup
|
||||||
|
|
||||||
|
```rust
|
||||||
|
// eprintln! ide na stderr (nie stdout)
|
||||||
|
eprintln!("Chyba: súbor neexistuje");
|
||||||
|
|
||||||
|
// V praxi: normálne správy cez println!, chyby cez eprintln!
|
||||||
|
```
|
||||||
|
|
||||||
|
### Úlohy 1
|
||||||
|
|
||||||
|
**1a.** Vypíš tabuľku 3 produktov s názvom (zarovnaný vľavo na 15), cenou (zarovnaná vpravo na 8, 2 desatinné) a počtom (zarovnaný vpravo na 5):
|
||||||
|
```
|
||||||
|
Chlieb | 1.20 | 50
|
||||||
|
Mlieko | 0.89 | 120
|
||||||
|
Maslo | 2.49 | 30
|
||||||
|
```
|
||||||
|
|
||||||
|
**1b.** Máš Vec<(String, f64)> — mená a priemery. Vypíš ich zoradené podľa priemeru, formátované na 1 desatinné miesto.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Kapitola 2: stdin — čítanie vstupu
|
||||||
|
|
||||||
|
```rust
|
||||||
|
use std::io;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
// Základné čítanie riadku
|
||||||
|
let mut vstup = String::new();
|
||||||
|
io::stdin().read_line(&mut vstup).unwrap();
|
||||||
|
// vstup teraz obsahuje text + '\n' na konci!
|
||||||
|
|
||||||
|
let vstup = vstup.trim(); // odstráň \n a medzery
|
||||||
|
println!("Napísal si: {}", vstup);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Krok po kroku
|
||||||
|
|
||||||
|
```rust
|
||||||
|
// 1. Vytvor prázdny String (buffer)
|
||||||
|
let mut vstup = String::new();
|
||||||
|
|
||||||
|
// 2. Prečítaj riadok do bufferu
|
||||||
|
// read_line PRIDÁVA do stringu (neprepisuje!)
|
||||||
|
// Vracia Result<usize, io::Error> (počet prečítaných bajtov)
|
||||||
|
io::stdin().read_line(&mut vstup).unwrap();
|
||||||
|
|
||||||
|
// 3. VŽDY trimni — read_line pridáva '\n'
|
||||||
|
let vstup = vstup.trim();
|
||||||
|
```
|
||||||
|
|
||||||
|
### Čítanie čísla
|
||||||
|
|
||||||
|
```rust
|
||||||
|
fn nacitaj_cislo() -> Option<i32> {
|
||||||
|
let mut vstup = String::new();
|
||||||
|
io::stdin().read_line(&mut vstup).ok()?;
|
||||||
|
vstup.trim().parse().ok()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Použitie:
|
||||||
|
match nacitaj_cislo() {
|
||||||
|
Some(n) => println!("Číslo: {}", n),
|
||||||
|
None => println!("To nie je číslo"),
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Čítanie jedného znaku
|
||||||
|
|
||||||
|
```rust
|
||||||
|
fn nacitaj_znak() -> Option<char> {
|
||||||
|
let mut vstup = String::new();
|
||||||
|
std::io::stdin().read_line(&mut vstup).ok()?;
|
||||||
|
vstup.trim().chars().next()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Použitie:
|
||||||
|
match nacitaj_znak() {
|
||||||
|
Some(c) => println!("Znak: {}", c),
|
||||||
|
None => println!("Prázdny vstup"),
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Pozor: read_line pridáva, neprepisuje!
|
||||||
|
|
||||||
|
```rust
|
||||||
|
let mut vstup = String::new();
|
||||||
|
io::stdin().read_line(&mut vstup).unwrap(); // "ahoj\n"
|
||||||
|
io::stdin().read_line(&mut vstup).unwrap(); // "ahoj\nsvet\n" — PRIDALO!
|
||||||
|
|
||||||
|
// Ak chceš čítať viackrát, buď trimuj alebo vytvor nový String
|
||||||
|
let mut vstup = String::new();
|
||||||
|
io::stdin().read_line(&mut vstup).unwrap();
|
||||||
|
let prvy = vstup.trim().to_string();
|
||||||
|
|
||||||
|
vstup.clear(); // VYMAŽ pred ďalším čítaním!
|
||||||
|
io::stdin().read_line(&mut vstup).unwrap();
|
||||||
|
let druhy = vstup.trim().to_string();
|
||||||
|
```
|
||||||
|
|
||||||
|
### Úlohy 2
|
||||||
|
|
||||||
|
**2a.** Napíš program, ktorý prečíta meno a vek od používateľa a vypíše `"Ahoj Anna, máš 25 rokov"`. Vek parsuj na u32.
|
||||||
|
|
||||||
|
**2b.** Napíš funkciu `nacitaj_riadok() -> Option<String>` — prečíta riadok, trimne, vráti None ak je prázdny.
|
||||||
|
|
||||||
|
**2c.** Napíš funkciu `nacitaj_float() -> Option<f64>` — prečíta riadok, trimne, parsne na f64.
|
||||||
|
|
||||||
|
**2d.** Napíš program, ktorý opakovane číta čísla od používateľa kým nezadá "koniec". Na konci vypíše súčet.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Kapitola 3: Game loop — opakované čítanie
|
||||||
|
|
||||||
|
Na skúške je typický vzor: čítaj vstup v cykle, reaguj, skonči keď podmienka.
|
||||||
|
|
||||||
|
### Základný game loop
|
||||||
|
|
||||||
|
```rust
|
||||||
|
use std::io;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
loop {
|
||||||
|
print!("Zadaj príkaz: ");
|
||||||
|
|
||||||
|
let mut vstup = String::new();
|
||||||
|
io::stdin().read_line(&mut vstup).unwrap();
|
||||||
|
let vstup = vstup.trim();
|
||||||
|
|
||||||
|
match vstup {
|
||||||
|
"koniec" => {
|
||||||
|
println!("Zbohom!");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
"pomoc" => {
|
||||||
|
println!("Príkazy: koniec, pomoc");
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
println!("Neznámy príkaz: {}", vstup);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Game loop s parsovaním
|
||||||
|
|
||||||
|
```rust
|
||||||
|
loop {
|
||||||
|
print!("> ");
|
||||||
|
let mut vstup = String::new();
|
||||||
|
io::stdin().read_line(&mut vstup).unwrap();
|
||||||
|
let casti: Vec<&str> = vstup.trim().split_whitespace().collect();
|
||||||
|
|
||||||
|
if casti.is_empty() { continue; }
|
||||||
|
|
||||||
|
match casti[0] {
|
||||||
|
"pridaj" => {
|
||||||
|
if casti.len() < 2 {
|
||||||
|
println!("Použitie: pridaj <meno>");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
let meno = casti[1];
|
||||||
|
println!("Pridávam: {}", meno);
|
||||||
|
}
|
||||||
|
"vypis" => {
|
||||||
|
println!("Výpis...");
|
||||||
|
}
|
||||||
|
"koniec" => break,
|
||||||
|
_ => println!("Neznámy príkaz"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Úlohy 3
|
||||||
|
|
||||||
|
**3a.** Napíš jednoduchý kalkulátor. Používateľ zadáva `"5 + 3"`, `"10 - 4"`, `"koniec"`. Program počíta a vypisuje výsledok.
|
||||||
|
|
||||||
|
**3b.** Napíš program, kde používateľ opakovane háda číslo 1-100. Program povie "viac", "menej" alebo "správne". Použi `rand::Rng`.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Kapitola 4: Súborové I/O — čítanie
|
||||||
|
|
||||||
|
```rust
|
||||||
|
use std::fs;
|
||||||
|
|
||||||
|
// Prečítaj celý súbor naraz do String
|
||||||
|
let obsah: Result<String, std::io::Error> = fs::read_to_string("data.txt");
|
||||||
|
|
||||||
|
match obsah {
|
||||||
|
Ok(text) => println!("Obsah: {}", text),
|
||||||
|
Err(e) => println!("Chyba: {}", e),
|
||||||
|
}
|
||||||
|
|
||||||
|
// Skrátene s .ok()? v funkcii
|
||||||
|
fn nacitaj(cesta: &str) -> Option<String> {
|
||||||
|
fs::read_to_string(cesta).ok()
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Čítanie po riadkoch
|
||||||
|
|
||||||
|
```rust
|
||||||
|
use std::fs;
|
||||||
|
|
||||||
|
fn spracuj_subor(cesta: &str) {
|
||||||
|
let obsah = fs::read_to_string(cesta).unwrap();
|
||||||
|
for (i, riadok) in obsah.lines().enumerate() {
|
||||||
|
println!("{}: {}", i + 1, riadok);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### BufReader — efektívne čítanie po riadkoch
|
||||||
|
|
||||||
|
Pre veľké súbory je lepší BufReader — nečíta celý súbor do pamäte:
|
||||||
|
|
||||||
|
```rust
|
||||||
|
use std::fs::File;
|
||||||
|
use std::io::{BufRead, BufReader};
|
||||||
|
|
||||||
|
fn citaj_po_riadkoch(cesta: &str) -> Result<(), std::io::Error> {
|
||||||
|
let subor = File::open(cesta)?;
|
||||||
|
let citac = BufReader::new(subor);
|
||||||
|
|
||||||
|
for riadok in citac.lines() {
|
||||||
|
let riadok = riadok?; // každý riadok je Result
|
||||||
|
println!("{}", riadok);
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Čítanie bajtov
|
||||||
|
|
||||||
|
```rust
|
||||||
|
// Celý súbor ako bajty
|
||||||
|
let bajty: Vec<u8> = fs::read("obrazok.png").unwrap();
|
||||||
|
println!("Veľkosť: {} bajtov", bajty.len());
|
||||||
|
```
|
||||||
|
|
||||||
|
### Úlohy 4
|
||||||
|
|
||||||
|
**4a.** Napíš funkciu `pocet_riadkov(cesta: &str) -> Option<usize>` — prečíta súbor a vráti počet riadkov.
|
||||||
|
|
||||||
|
**4b.** Napíš funkciu `najdi_v_subore(cesta: &str, hladany: &str) -> Vec<String>` — vráti riadky, ktoré obsahujú hľadaný text.
|
||||||
|
|
||||||
|
**4c.** Napíš funkciu `nacitaj_cisla(cesta: &str) -> Option<Vec<i32>>` — súbor obsahuje jedno číslo na riadok. Prečítaj, parsuj, vráť Vec.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Kapitola 5: Súborové I/O — zápis
|
||||||
|
|
||||||
|
```rust
|
||||||
|
use std::fs;
|
||||||
|
|
||||||
|
// Zapíš celý String do súboru (prepíše ak existuje!)
|
||||||
|
fs::write("data.txt", "Ahoj svet\nDruhý riadok\n").unwrap();
|
||||||
|
|
||||||
|
// Bezpečná verzia v funkcii
|
||||||
|
fn uloz(cesta: &str, obsah: &str) -> bool {
|
||||||
|
fs::write(cesta, obsah).is_ok()
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Pridávanie na koniec (append)
|
||||||
|
|
||||||
|
```rust
|
||||||
|
use std::fs::OpenOptions;
|
||||||
|
use std::io::Write;
|
||||||
|
|
||||||
|
fn pripis(cesta: &str, text: &str) -> bool {
|
||||||
|
let vysledok = OpenOptions::new()
|
||||||
|
.create(true) // vytvor ak neexistuje
|
||||||
|
.append(true) // pridávaj na koniec
|
||||||
|
.open(cesta);
|
||||||
|
|
||||||
|
match vysledok {
|
||||||
|
Ok(mut subor) => {
|
||||||
|
writeln!(subor, "{}", text).is_ok()
|
||||||
|
}
|
||||||
|
Err(_) => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### BufWriter — efektívny zápis
|
||||||
|
|
||||||
|
```rust
|
||||||
|
use std::fs::File;
|
||||||
|
use std::io::{BufWriter, Write};
|
||||||
|
|
||||||
|
fn zapis_vela_riadkov(cesta: &str, riadky: &[String]) -> bool {
|
||||||
|
let Ok(subor) = File::create(cesta) else {
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
let mut writer = BufWriter::new(subor);
|
||||||
|
for riadok in riadky {
|
||||||
|
if writeln!(writer, "{}", riadok).is_err() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
true
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Úlohy 5
|
||||||
|
|
||||||
|
**5a.** Napíš funkciu `uloz_riadky(cesta: &str, riadky: &[String]) -> bool` — ulož vektor riadkov do súboru, každý na nový riadok.
|
||||||
|
|
||||||
|
**5b.** Napíš funkciu `pridaj_riadok(cesta: &str, riadok: &str) -> bool` — pridaj riadok na koniec súboru.
|
||||||
|
|
||||||
|
**5c.** Napíš program, ktorý číta mená od používateľa a ukladá ich do `"mena.txt"`. Keď zadá "koniec", skončí.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Kapitola 6: PathBuf a Path
|
||||||
|
|
||||||
|
`PathBuf` je ako `String` pre cesty k súborom. `Path` je ako `&str`.
|
||||||
|
|
||||||
|
```rust
|
||||||
|
use std::path::{PathBuf, Path};
|
||||||
|
|
||||||
|
// Vytváranie PathBuf
|
||||||
|
let cesta = PathBuf::from("data/subory/kniznica.json");
|
||||||
|
let cesta: PathBuf = "data.json".into();
|
||||||
|
|
||||||
|
// Z &str
|
||||||
|
let cesta = Path::new("data.json");
|
||||||
|
|
||||||
|
// Konverzia
|
||||||
|
let pathbuf = PathBuf::from("data.json");
|
||||||
|
let path: &Path = &pathbuf; // PathBuf → &Path
|
||||||
|
let path: &Path = pathbuf.as_path(); // to isté
|
||||||
|
|
||||||
|
// Užitočné metódy
|
||||||
|
let cesta = PathBuf::from("/home/user/data.json");
|
||||||
|
cesta.exists(); // existuje súbor?
|
||||||
|
cesta.is_file(); // je to súbor?
|
||||||
|
cesta.is_dir(); // je to priečinok?
|
||||||
|
cesta.extension(); // Some("json")
|
||||||
|
cesta.file_name(); // Some("data.json")
|
||||||
|
cesta.parent(); // Some("/home/user")
|
||||||
|
|
||||||
|
// Skladanie ciest
|
||||||
|
let mut cesta = PathBuf::from("/home/user");
|
||||||
|
cesta.push("dokumenty");
|
||||||
|
cesta.push("subor.txt");
|
||||||
|
// /home/user/dokumenty/subor.txt
|
||||||
|
```
|
||||||
|
|
||||||
|
### Na skúške — PathBuf v clape
|
||||||
|
|
||||||
|
```rust
|
||||||
|
use clap::Parser;
|
||||||
|
use std::path::PathBuf;
|
||||||
|
|
||||||
|
#[derive(Parser)]
|
||||||
|
struct Args {
|
||||||
|
#[arg(short, long, default_value = "data.json")]
|
||||||
|
subor: PathBuf,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let args = Args::parse();
|
||||||
|
// args.subor je PathBuf — predávaš priamo do funkcií
|
||||||
|
let kniznica = Kniznica::nacitaj_zo_suboru(&args.subor)
|
||||||
|
.unwrap_or_default();
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Funkcie berúce cestu
|
||||||
|
|
||||||
|
```rust
|
||||||
|
// Berie &PathBuf — funguje s PathBuf
|
||||||
|
fn nacitaj(cesta: &PathBuf) -> Option<String> {
|
||||||
|
std::fs::read_to_string(cesta).ok()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Lepšie: berie &Path — funguje s PathBuf aj &str
|
||||||
|
fn nacitaj(cesta: &Path) -> Option<String> {
|
||||||
|
std::fs::read_to_string(cesta).ok()
|
||||||
|
}
|
||||||
|
|
||||||
|
// fs::read_to_string berie impl AsRef<Path> — prijme takmer čokoľvek
|
||||||
|
// Preto funguje:
|
||||||
|
fs::read_to_string("data.json"); // &str
|
||||||
|
fs::read_to_string(String::from("data.json")); // String
|
||||||
|
fs::read_to_string(PathBuf::from("data.json")); // PathBuf
|
||||||
|
fs::read_to_string(&pathbuf); // &PathBuf
|
||||||
|
```
|
||||||
|
|
||||||
|
### Úlohy 6
|
||||||
|
|
||||||
|
**6a.** Vytvor PathBuf z `"/home/user/docs"`. Pridaj `"projekt"` a `"data.json"`. Vypíš celú cestu.
|
||||||
|
|
||||||
|
**6b.** Máš PathBuf. Vypíš: existuje? Je súbor? Prípona? Názov súboru? Rodičovský priečinok?
|
||||||
|
|
||||||
|
**6c.** Prečo na skúške metóda `nacitaj_zo_suboru` berie `&PathBuf` a nie `&str`?
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Kapitola 7: serde JSON I/O — kompletný vzor
|
||||||
|
|
||||||
|
Toto je vzor na každej skúške. Kombinácia fs + serde_json.
|
||||||
|
|
||||||
|
```rust
|
||||||
|
use std::fs;
|
||||||
|
use std::path::PathBuf;
|
||||||
|
use serde::{Serialize, Deserialize};
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Default)]
|
||||||
|
struct Kniznica {
|
||||||
|
knihy: Vec<Kniha>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Clone)]
|
||||||
|
struct Kniha {
|
||||||
|
nazov: String,
|
||||||
|
autor: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Kniznica {
|
||||||
|
// ČÍTANIE: súbor → String → štruktúra
|
||||||
|
fn nacitaj_zo_suboru(cesta: &PathBuf) -> Option<Kniznica> {
|
||||||
|
// 1. fs::read_to_string — súbor → String
|
||||||
|
let raw = fs::read_to_string(cesta).ok()?;
|
||||||
|
// 2. serde_json::from_str — String → štruktúra
|
||||||
|
serde_json::from_str(&raw).ok()
|
||||||
|
}
|
||||||
|
|
||||||
|
// ZÁPIS: štruktúra → String → súbor
|
||||||
|
fn uloz_do_suboru(&self, cesta: &PathBuf) -> bool {
|
||||||
|
// 1. serde_json::to_string_pretty — štruktúra → String
|
||||||
|
let Ok(json) = serde_json::to_string_pretty(&self) else {
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
// 2. fs::write — String → súbor
|
||||||
|
fs::write(cesta, json).is_ok()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Celý tok dát:
|
||||||
|
|
||||||
|
```
|
||||||
|
ČÍTANIE:
|
||||||
|
súbor na disku
|
||||||
|
→ fs::read_to_string → String s JSON textom
|
||||||
|
→ serde_json::from_str → Rust štruktúra
|
||||||
|
|
||||||
|
ZÁPIS:
|
||||||
|
Rust štruktúra
|
||||||
|
→ serde_json::to_string_pretty → String s JSON textom
|
||||||
|
→ fs::write → súbor na disku
|
||||||
|
```
|
||||||
|
|
||||||
|
### Použitie v main
|
||||||
|
|
||||||
|
```rust
|
||||||
|
fn main() {
|
||||||
|
let cesta = PathBuf::from("kniznica.json");
|
||||||
|
|
||||||
|
// Načítaj alebo vytvor prázdnu
|
||||||
|
let mut kniznica = Kniznica::nacitaj_zo_suboru(&cesta)
|
||||||
|
.unwrap_or_default();
|
||||||
|
|
||||||
|
// Urob niečo...
|
||||||
|
kniznica.knihy.push(Kniha {
|
||||||
|
nazov: "Duna".into(),
|
||||||
|
autor: "Herbert".into(),
|
||||||
|
});
|
||||||
|
|
||||||
|
// Ulož
|
||||||
|
kniznica.uloz_do_suboru(&cesta);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Čo sa deje keď súbor neexistuje
|
||||||
|
|
||||||
|
```rust
|
||||||
|
// fs::read_to_string("neexistuje.json")
|
||||||
|
// → Err(io::Error)
|
||||||
|
// → .ok() → None
|
||||||
|
// → ? → vráti None z funkcie
|
||||||
|
|
||||||
|
// Preto:
|
||||||
|
Kniznica::nacitaj_zo_suboru(&PathBuf::from("neexistuje.json"))
|
||||||
|
// → None
|
||||||
|
|
||||||
|
// A v main:
|
||||||
|
let mut kniznica = Kniznica::nacitaj_zo_suboru(&cesta)
|
||||||
|
.unwrap_or_default();
|
||||||
|
// None → unwrap_or_default() → Kniznica::default() → Kniznica { knihy: vec![] }
|
||||||
|
```
|
||||||
|
|
||||||
|
### Úlohy 7
|
||||||
|
|
||||||
|
**7a.** Napíš `nacitaj_zo_suboru` a `uloz_do_suboru` pre:
|
||||||
|
```rust
|
||||||
|
#[derive(Serialize, Deserialize, Default)]
|
||||||
|
struct TodoList {
|
||||||
|
ulohy: Vec<Todo>,
|
||||||
|
}
|
||||||
|
#[derive(Serialize, Deserialize, Clone)]
|
||||||
|
struct Todo {
|
||||||
|
text: String,
|
||||||
|
hotova: bool,
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**7b.** Napíš program, ktorý:
|
||||||
|
1. Načíta TodoList z "todo.json"
|
||||||
|
2. Pridá novú úlohu
|
||||||
|
3. Uloží späť
|
||||||
|
4. Znova načíta a vypíše počet úloh (overenie)
|
||||||
|
|
||||||
|
**7c.** Čo sa stane ak `serde_json::to_string_pretty` zlyhá? Kedy sa to stane? (Hint: takmer nikdy pre bežné štruktúry.)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Kapitola 8: IOManager trait — vzor zo skúšky
|
||||||
|
|
||||||
|
Na skúške sa I/O abstrahuje cez trait. Toto umožňuje testovanie bez konzoly.
|
||||||
|
|
||||||
|
### Prečo nie priamo stdin?
|
||||||
|
|
||||||
|
```rust
|
||||||
|
// PROBLÉM: toto nejde testovať automaticky
|
||||||
|
fn hraj(hra: &mut Hra) {
|
||||||
|
let mut vstup = String::new();
|
||||||
|
io::stdin().read_line(&mut vstup).unwrap(); // čaká na konzolu
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Riešenie: IOManager trait
|
||||||
|
|
||||||
|
```rust
|
||||||
|
// 1. Definuj trait — AKO získať vstup
|
||||||
|
pub trait IOManager {
|
||||||
|
fn ziskaj_pismeno(&mut self) -> char;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. Reálna implementácia — čítaj z konzoly
|
||||||
|
pub struct ConsoleIOManager;
|
||||||
|
|
||||||
|
impl IOManager for ConsoleIOManager {
|
||||||
|
fn ziskaj_pismeno(&mut self) -> char {
|
||||||
|
let mut vstup = String::new();
|
||||||
|
std::io::stdin().read_line(&mut vstup).unwrap();
|
||||||
|
vstup.trim().chars().next().unwrap_or(' ')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. Metóda berie impl IOManager — funguje s čímkoľvek
|
||||||
|
impl Hra {
|
||||||
|
pub fn hraj(&mut self, mut io: impl IOManager) {
|
||||||
|
while !self.je_koniec_hry() {
|
||||||
|
println!("Slovo: {}", self.daj_slovo_skryto());
|
||||||
|
let pismeno = io.ziskaj_pismeno();
|
||||||
|
let vysledok = self.tipni_pismeno(pismeno);
|
||||||
|
println!("{}", vysledok);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 4. Volanie v main
|
||||||
|
fn main() {
|
||||||
|
let mut hra = Hra::new("rust");
|
||||||
|
hra.hraj(ConsoleIOManager); // predáme implementáciu
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### ConsoleIOManager — prázdna štruktúra
|
||||||
|
|
||||||
|
```rust
|
||||||
|
// Prázdna štruktúra — žiadne členy
|
||||||
|
pub struct ConsoleIOManager;
|
||||||
|
|
||||||
|
// Toto nie je typ s poľami. Je to "unit struct".
|
||||||
|
// Vytváraš ju bez {} :
|
||||||
|
let io = ConsoleIOManager; // OK
|
||||||
|
// let io = ConsoleIOManager {}; // tiež OK ale zbytočné
|
||||||
|
```
|
||||||
|
|
||||||
|
### Rozšírený IOManager
|
||||||
|
|
||||||
|
Niekedy trait má viac metód:
|
||||||
|
|
||||||
|
```rust
|
||||||
|
pub trait IOManager {
|
||||||
|
fn ziskaj_pismeno(&mut self) -> char;
|
||||||
|
fn zobraz_spravu(&self, sprava: &str);
|
||||||
|
fn zobraz_stav(&self, zivoty: u8, slovo: &str, skusane: &[char]);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct ConsoleIOManager;
|
||||||
|
|
||||||
|
impl IOManager for ConsoleIOManager {
|
||||||
|
fn ziskaj_pismeno(&mut self) -> char {
|
||||||
|
print!("Zadaj písmeno: ");
|
||||||
|
let mut vstup = String::new();
|
||||||
|
std::io::stdin().read_line(&mut vstup).unwrap();
|
||||||
|
vstup.trim().chars().next().unwrap_or(' ')
|
||||||
|
}
|
||||||
|
|
||||||
|
fn zobraz_spravu(&self, sprava: &str) {
|
||||||
|
println!("{}", sprava);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn zobraz_stav(&self, zivoty: u8, slovo: &str, skusane: &[char]) {
|
||||||
|
println!("Životov: {}", zivoty);
|
||||||
|
println!("Slovo: {}", slovo);
|
||||||
|
println!("Skúšané: {:?}", skusane);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Úlohy 8
|
||||||
|
|
||||||
|
**8a.** Napíš trait `Vstup` s metódou `nacitaj_cislo(&mut self) -> Option<i32>`. Implementuj:
|
||||||
|
- `KonzolaVstup` — číta z stdin
|
||||||
|
- `TestovaciVstup { cisla: Vec<i32>, index: usize }` — vracia predpripravené čísla
|
||||||
|
|
||||||
|
**8b.** Napíš funkciu `hadaj_cislo(tajne: i32, mut vstup: impl Vstup)` — hra na hádanie čísla. Používa trait namiesto priameho stdin.
|
||||||
|
|
||||||
|
**8c.** Máš IOManager z príkladu vyššie. Napíš `TestIOManager`:
|
||||||
|
```rust
|
||||||
|
struct TestIOManager {
|
||||||
|
odpovede: Vec<char>,
|
||||||
|
index: usize,
|
||||||
|
}
|
||||||
|
```
|
||||||
|
Implementuj IOManager — `ziskaj_pismeno` vráti ďalšie písmeno z `odpovede`.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Kapitola 9: flush — print! bez nového riadku
|
||||||
|
|
||||||
|
`print!` nevyprázdni buffer automaticky. Ak chceš aby sa text zobrazil okamžite pred čítaním vstupu:
|
||||||
|
|
||||||
|
```rust
|
||||||
|
use std::io::{self, Write};
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
print!("Zadaj meno: ");
|
||||||
|
io::stdout().flush().unwrap(); // DÔLEŽITÉ! Vynúti výpis
|
||||||
|
|
||||||
|
let mut vstup = String::new();
|
||||||
|
io::stdin().read_line(&mut vstup).unwrap();
|
||||||
|
println!("Ahoj, {}!", vstup.trim());
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Bez `flush()` sa "Zadaj meno: " môže zobraziť až po tom, čo zadáš vstup. S `flush()` sa zobrazí hneď.
|
||||||
|
|
||||||
|
```rust
|
||||||
|
// Kompletný vzor pre prompt
|
||||||
|
fn prompt(text: &str) -> String {
|
||||||
|
print!("{}", text);
|
||||||
|
io::stdout().flush().unwrap();
|
||||||
|
let mut vstup = String::new();
|
||||||
|
io::stdin().read_line(&mut vstup).unwrap();
|
||||||
|
vstup.trim().to_string()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Použitie:
|
||||||
|
let meno = prompt("Meno: ");
|
||||||
|
let vek = prompt("Vek: ");
|
||||||
|
```
|
||||||
|
|
||||||
|
### Úlohy 9
|
||||||
|
|
||||||
|
**9a.** Napíš funkciu `prompt(text: &str) -> String` s flush. Použi ju na prečítanie mena a veku.
|
||||||
|
|
||||||
|
**9b.** Napíš funkciu `prompt_cislo(text: &str) -> Option<i32>` — zobrazí text, prečíta, parsne.
|
||||||
|
|
||||||
|
**9c.** Napíš interaktívny program, ktorý používa prompt funkciu na čítanie príkazov v cykle.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Kapitola 10: Prehľad a vzory
|
||||||
|
|
||||||
|
### Rýchly prehľad: čo kedy použiť
|
||||||
|
|
||||||
|
| Chcem... | Použi |
|
||||||
|
|----------|-------|
|
||||||
|
| Čítať celý súbor | `fs::read_to_string(cesta)` |
|
||||||
|
| Zapísať celý súbor | `fs::write(cesta, obsah)` |
|
||||||
|
| Čítať po riadkoch (malý súbor) | `fs::read_to_string` + `.lines()` |
|
||||||
|
| Čítať po riadkoch (veľký súbor) | `BufReader::new(File::open)` + `.lines()` |
|
||||||
|
| Pripísať na koniec | `OpenOptions::new().append(true)` |
|
||||||
|
| Čítať z konzoly | `io::stdin().read_line(&mut buf)` |
|
||||||
|
| Prompt bez newline | `print!()` + `io::stdout().flush()` |
|
||||||
|
| JSON: súbor → štruktúra | `fs::read_to_string` + `serde_json::from_str` |
|
||||||
|
| JSON: štruktúra → súbor | `serde_json::to_string_pretty` + `fs::write` |
|
||||||
|
| Testovateľný I/O | `trait IOManager` + `impl IOManager for ...` |
|
||||||
|
|
||||||
|
### Vzor: kompletné menu programu
|
||||||
|
|
||||||
|
```rust
|
||||||
|
use std::io::{self, Write};
|
||||||
|
use std::path::PathBuf;
|
||||||
|
|
||||||
|
fn prompt(text: &str) -> String {
|
||||||
|
print!("{}", text);
|
||||||
|
io::stdout().flush().unwrap();
|
||||||
|
let mut vstup = String::new();
|
||||||
|
io::stdin().read_line(&mut vstup).unwrap();
|
||||||
|
vstup.trim().to_string()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let cesta = PathBuf::from("data.json");
|
||||||
|
let mut kniznica = Kniznica::nacitaj_zo_suboru(&cesta)
|
||||||
|
.unwrap_or_default();
|
||||||
|
|
||||||
|
loop {
|
||||||
|
println!("\n--- KNIŽNICA ---");
|
||||||
|
println!("1. Pridaj knihu");
|
||||||
|
println!("2. Vypíš knihy");
|
||||||
|
println!("3. Hľadaj");
|
||||||
|
println!("4. Koniec");
|
||||||
|
|
||||||
|
let volba = prompt("Vyber: ");
|
||||||
|
|
||||||
|
match volba.as_str() {
|
||||||
|
"1" => {
|
||||||
|
let nazov = prompt("Názov: ");
|
||||||
|
let autor = prompt("Autor: ");
|
||||||
|
// ... pridaj knihu
|
||||||
|
kniznica.uloz_do_suboru(&cesta);
|
||||||
|
println!("Pridané.");
|
||||||
|
}
|
||||||
|
"2" => {
|
||||||
|
for kniha in &kniznica.knihy {
|
||||||
|
println!("{}", kniha);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"3" => {
|
||||||
|
let vyraz = prompt("Hľadaj: ");
|
||||||
|
// ... hľadaj
|
||||||
|
}
|
||||||
|
"4" => {
|
||||||
|
println!("Zbohom!");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
_ => println!("Neznáma voľba"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Úlohy 10
|
||||||
|
|
||||||
|
**10a.** Napíš kompletný interaktívny program pre TODO list:
|
||||||
|
- Pridaj úlohu (prompt názov)
|
||||||
|
- Označ ako hotovú (prompt index)
|
||||||
|
- Vypíš všetky
|
||||||
|
- Ulož do JSON
|
||||||
|
- Koniec
|
||||||
|
|
||||||
|
**10b.** Napíš program, ktorý prečíta CSV súbor (meno,vek,mesto), sparsuje riadky do Vec štruktúr, a umožní hľadanie podľa mesta.
|
||||||
|
|
||||||
|
**10c.** Implementuj kompletný IOManager trait pre hru Obesenec. Vytvor aj TestIOManager, ktorý automaticky „hrá" hru s predpripravenými písmenami.
|
||||||
674
priprava/rust_priprava14.md
Normal file
674
priprava/rust_priprava14.md
Normal file
@@ -0,0 +1,674 @@
|
|||||||
|
# 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.10"
|
||||||
|
```
|
||||||
|
|
||||||
|
Najjednoduchší import — dáva ti všetko bežné:
|
||||||
|
```rust
|
||||||
|
use rand::prelude::*;
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Kapitola 1: Generátor — rand::rng()
|
||||||
|
|
||||||
|
```rust
|
||||||
|
use rand::Rng;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let mut rng = rand::rng();
|
||||||
|
|
||||||
|
// 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.random();
|
||||||
|
println!("{}", desatinne);
|
||||||
|
|
||||||
|
// Náhodné bool
|
||||||
|
let minca: bool = rng.random();
|
||||||
|
println!("{}", minca);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
`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.
|
||||||
|
|
||||||
|
**1c.** Čo je zle?
|
||||||
|
```rust
|
||||||
|
let rng = rand::rng();
|
||||||
|
let cislo: i32 = rng.random();
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Kapitola 2: random_range — číslo v rozsahu
|
||||||
|
|
||||||
|
```rust
|
||||||
|
use rand::Rng;
|
||||||
|
|
||||||
|
let mut rng = rand::rng();
|
||||||
|
|
||||||
|
// Od 1 do 10 (vrátane oboch)
|
||||||
|
let cislo: i32 = rng.random_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.random_range(0.0..1.0);
|
||||||
|
|
||||||
|
// Náhodný index do vektora
|
||||||
|
let vektor = vec!["a", "b", "c", "d", "e"];
|
||||||
|
let index: usize = rng.random_range(0..vektor.len());
|
||||||
|
let nahodny_prvok = &vektor[index];
|
||||||
|
```
|
||||||
|
|
||||||
|
| Zápis | Rozsah | Príklad |
|
||||||
|
|-------|--------|---------|
|
||||||
|
| `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, spočítaj výskyty každého čísla (HashMap).
|
||||||
|
|
||||||
|
**2b.** Vygeneruj náhodné heslo — 8 znakov a-z. Hint: `rng.random_range(b'a'..=b'z') as char`.
|
||||||
|
|
||||||
|
**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.
|
||||||
|
|
||||||
|
```rust
|
||||||
|
use rand::seq::IndexedRandom; // TOTO TREBA!
|
||||||
|
|
||||||
|
let mut rng = rand::rng();
|
||||||
|
|
||||||
|
let ovocie = vec!["jablko", "hruška", "banán", "pomaranč"];
|
||||||
|
|
||||||
|
// choose — vráti Option (None ak prázdny Vec)
|
||||||
|
let nahodne = ovocie.choose(&mut rng);
|
||||||
|
// Some(&"hruška")
|
||||||
|
|
||||||
|
match nahodne {
|
||||||
|
Some(o) => println!("Vybrané: {}", o),
|
||||||
|
None => println!("Prázdny zoznam"),
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Import:** `use rand::seq::IndexedRandom;` — bez tohto `choose` nefunguje!
|
||||||
|
|
||||||
|
Alebo použi `use rand::prelude::*;` — ten to zahŕňa.
|
||||||
|
|
||||||
|
### choose s Vec<String>
|
||||||
|
|
||||||
|
```rust
|
||||||
|
use rand::seq::IndexedRandom;
|
||||||
|
|
||||||
|
let slova = vec!["pes".to_string(), "mačka".to_string(), "kôň".to_string()];
|
||||||
|
let mut rng = rand::rng();
|
||||||
|
|
||||||
|
let nahodne: Option<&String> = slova.choose(&mut rng);
|
||||||
|
// Some(&"mačka")
|
||||||
|
```
|
||||||
|
|
||||||
|
### choose na skúške — SpravcaHry.vytvor_novu_hru
|
||||||
|
|
||||||
|
```rust
|
||||||
|
use rand::seq::IndexedRandom;
|
||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
|
struct SpravcaHry {
|
||||||
|
slovnik: HashMap<String, Vec<String>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SpravcaHry {
|
||||||
|
fn vytvor_novu_hru(&self, kategoria: &str) -> Option<Hra> {
|
||||||
|
// 1. Nájdi kategóriu
|
||||||
|
let slova = self.slovnik.get(kategoria)?;
|
||||||
|
|
||||||
|
// 2. Prázdna → None
|
||||||
|
if slova.is_empty() {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. Vyber náhodné slovo
|
||||||
|
let mut rng = rand::rng();
|
||||||
|
let slovo = slova.choose(&mut rng)?;
|
||||||
|
|
||||||
|
// 4. Vytvor hru
|
||||||
|
Some(Hra::new(slovo))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Krok po kroku:
|
||||||
|
```
|
||||||
|
slovnik = {"zvierata": ["pes", "mačka", "kôň"]}
|
||||||
|
|
||||||
|
kategoria = "zvierata"
|
||||||
|
→ slovnik.get("zvierata") → Some(&["pes", "mačka", "kôň"])
|
||||||
|
→ slova.choose(&mut rng) → Some(&"mačka")
|
||||||
|
→ Hra::new("mačka")
|
||||||
|
|
||||||
|
kategoria = "neexistuje"
|
||||||
|
→ slovnik.get("neexistuje") → None
|
||||||
|
→ ? → return None
|
||||||
|
```
|
||||||
|
|
||||||
|
### Úlohy 3
|
||||||
|
|
||||||
|
**3a.** Máš Vec mien. Vyber náhodné a vypíš.
|
||||||
|
|
||||||
|
**3b.** Máš HashMap<String, Vec<String>> (kategória → slová). Napíš funkciu:
|
||||||
|
```rust
|
||||||
|
fn nahodne_slovo(slovnik: &HashMap<String, Vec<String>>, kategoria: &str) -> Option<&String>
|
||||||
|
```
|
||||||
|
|
||||||
|
**3c.** Čo sa stane ak zavoláš `.choose()` na prázdnom vektore?
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Kapitola 4: sample — viac náhodných prvkov
|
||||||
|
|
||||||
|
V novej verzii rand sa `choose_multiple` nahradil metódou `sample`:
|
||||||
|
|
||||||
|
```rust
|
||||||
|
use rand::seq::IndexedRandom;
|
||||||
|
|
||||||
|
let cisla = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
|
||||||
|
let mut rng = rand::rng();
|
||||||
|
|
||||||
|
// Vyber 3 náhodné prvky (BEZ opakovania)
|
||||||
|
let vybrane: Vec<&i32> = cisla.sample(&mut rng, 3).collect();
|
||||||
|
// napr. [&7, &2, &9]
|
||||||
|
|
||||||
|
// 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
|
||||||
|
|
||||||
|
```rust
|
||||||
|
struct Kviz {
|
||||||
|
otazky: Vec<Otazka>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Kviz {
|
||||||
|
fn nahodnych_n(&self, n: usize) -> Vec<&Otazka> {
|
||||||
|
let mut rng = rand::rng();
|
||||||
|
self.otazky.sample(&mut rng, n).collect()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Úlohy 4
|
||||||
|
|
||||||
|
**4a.** Máš 20 študentov. Vyber 5 náhodných na skúšanie.
|
||||||
|
|
||||||
|
**4b.** Máš balíček kariet (Vec<String>). Rozdaj 7 kariet.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Kapitola 5: shuffle — zamiešanie
|
||||||
|
|
||||||
|
```rust
|
||||||
|
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::rng();
|
||||||
|
|
||||||
|
// shuffle — zamieša NA MIESTE (mení Vec)
|
||||||
|
cisla.shuffle(&mut rng);
|
||||||
|
// napr. [7, 2, 9, 1, 5, 3, 10, 4, 8, 6]
|
||||||
|
```
|
||||||
|
|
||||||
|
**Import:** `use rand::seq::SliceRandom;` — shuffle je v SliceRandom, nie IndexedRandom!
|
||||||
|
|
||||||
|
### Kedy čo
|
||||||
|
|
||||||
|
| 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
|
||||||
|
|
||||||
|
```rust
|
||||||
|
use rand::seq::SliceRandom;
|
||||||
|
|
||||||
|
impl Kviz {
|
||||||
|
fn hraj(&mut self) {
|
||||||
|
let mut rng = rand::rng();
|
||||||
|
self.otazky.shuffle(&mut rng);
|
||||||
|
|
||||||
|
for otazka in &self.otazky {
|
||||||
|
println!("{}", otazka.text);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Úlohy 5
|
||||||
|
|
||||||
|
**5a.** Máš vektor kariet. Zamiešaj. Vypíš prvých 5.
|
||||||
|
|
||||||
|
**5b.** Čo je zle?
|
||||||
|
```rust
|
||||||
|
let cisla = vec![1, 2, 3, 4, 5];
|
||||||
|
cisla.shuffle(&mut rand::rng());
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Kapitola 6: Náhodné znaky a reťazce
|
||||||
|
|
||||||
|
```rust
|
||||||
|
use rand::Rng;
|
||||||
|
use rand::distr::Alphanumeric; // distr, nie distributions!
|
||||||
|
|
||||||
|
let mut rng = rand::rng();
|
||||||
|
|
||||||
|
// Náhodný ASCII znak a-z
|
||||||
|
let znak: char = rng.random_range(b'a'..=b'z') as char;
|
||||||
|
|
||||||
|
// Náhodný veľký znak A-Z
|
||||||
|
let znak: char = rng.random_range(b'A'..=b'Z') as char;
|
||||||
|
|
||||||
|
// Alfanumerický reťazec (a-z, A-Z, 0-9)
|
||||||
|
let heslo: String = (0..12)
|
||||||
|
.map(|_| rng.sample(Alphanumeric) as char)
|
||||||
|
.collect();
|
||||||
|
// napr. "a7Bk9xQ2mF1p"
|
||||||
|
```
|
||||||
|
|
||||||
|
### Výber náhodného znaku z reťazca
|
||||||
|
|
||||||
|
```rust
|
||||||
|
use rand::seq::IndexedRandom;
|
||||||
|
|
||||||
|
let abeceda: Vec<char> = "abcdefghijklmnopqrstuvwxyz".chars().collect();
|
||||||
|
let mut rng = rand::rng();
|
||||||
|
|
||||||
|
let nahodny_znak = abeceda.choose(&mut rng);
|
||||||
|
// Some(&'m')
|
||||||
|
```
|
||||||
|
|
||||||
|
### Úlohy 6
|
||||||
|
|
||||||
|
**6a.** Vygeneruj heslo: 10 znakov, len malé písmená a-z.
|
||||||
|
|
||||||
|
**6b.** Vygeneruj náhodné meno: veľké prvé + 4 malé písmená.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Kapitola 7: random_bool — pravdepodobnosť
|
||||||
|
|
||||||
|
```rust
|
||||||
|
use rand::Rng;
|
||||||
|
|
||||||
|
let mut rng = rand::rng();
|
||||||
|
|
||||||
|
// 50% šanca na true
|
||||||
|
let minca: bool = rng.random_bool(0.5);
|
||||||
|
|
||||||
|
// 70% šanca na true
|
||||||
|
let dost_casto: bool = rng.random_bool(0.7);
|
||||||
|
|
||||||
|
// 10% šanca na true
|
||||||
|
let zriedka: bool = rng.random_bool(0.1);
|
||||||
|
```
|
||||||
|
|
||||||
|
### Úlohy 7
|
||||||
|
|
||||||
|
**7a.** Simuluj 1000 hodov mincou. Koľkokrát padol orol (true)?
|
||||||
|
|
||||||
|
**7b.** Funkcia vráti "Výhra!" s 15% pravdepodobnosťou, inak "Skús znova".
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Kapitola 8: Kombinácia s IO — interaktívne hry
|
||||||
|
|
||||||
|
### Hádaj číslo
|
||||||
|
|
||||||
|
```rust
|
||||||
|
use rand::Rng;
|
||||||
|
use std::io::{self, Write};
|
||||||
|
|
||||||
|
fn prompt(text: &str) -> String {
|
||||||
|
print!("{}", text);
|
||||||
|
io::stdout().flush().unwrap();
|
||||||
|
let mut vstup = String::new();
|
||||||
|
io::stdin().read_line(&mut vstup).unwrap();
|
||||||
|
vstup.trim().to_string()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
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!");
|
||||||
|
|
||||||
|
loop {
|
||||||
|
let vstup = prompt("Tvoj tip: ");
|
||||||
|
let tip: i32 = match vstup.parse() {
|
||||||
|
Ok(n) => n,
|
||||||
|
Err(_) => {
|
||||||
|
println!("Zadaj číslo!");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
pokusy += 1;
|
||||||
|
|
||||||
|
if tip < tajne {
|
||||||
|
println!("Viac!");
|
||||||
|
} else if tip > tajne {
|
||||||
|
println!("Menej!");
|
||||||
|
} else {
|
||||||
|
println!("Správne! Uhádol si na {} pokusov.", pokusy);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Obesenec s náhodným slovom
|
||||||
|
|
||||||
|
```rust
|
||||||
|
use rand::seq::IndexedRandom;
|
||||||
|
use std::collections::{HashSet, HashMap};
|
||||||
|
use std::io::{self, Write};
|
||||||
|
|
||||||
|
fn nacitaj_znak() -> Option<char> {
|
||||||
|
print!("Zadaj písmeno: ");
|
||||||
|
io::stdout().flush().unwrap();
|
||||||
|
let mut vstup = String::new();
|
||||||
|
io::stdin().read_line(&mut vstup).ok()?;
|
||||||
|
vstup.trim().to_lowercase().chars().next()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
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::rng();
|
||||||
|
let kategorie: Vec<&&str> = slovnik.keys().collect();
|
||||||
|
let kategoria = **kategorie.choose(&mut rng).unwrap();
|
||||||
|
let slova = &slovnik[kategoria];
|
||||||
|
let slovo = *slova.choose(&mut rng).unwrap();
|
||||||
|
|
||||||
|
println!("Kategória: {}", kategoria);
|
||||||
|
|
||||||
|
let mut uhadnute: HashSet<char> = HashSet::new();
|
||||||
|
let mut skusane: HashSet<char> = HashSet::new();
|
||||||
|
let mut zivoty: u8 = 6;
|
||||||
|
|
||||||
|
loop {
|
||||||
|
let zobrazene: String = slovo.chars().map(|c| {
|
||||||
|
if uhadnute.contains(&c) { c } else { '_' }
|
||||||
|
}).collect();
|
||||||
|
println!("\n{} (životov: {})", zobrazene, zivoty);
|
||||||
|
|
||||||
|
if slovo.chars().all(|c| uhadnute.contains(&c)) {
|
||||||
|
println!("Vyhral si! Slovo bolo: {}", slovo);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if zivoty == 0 {
|
||||||
|
println!("Prehral si! Slovo bolo: {}", slovo);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
let Some(pismeno) = nacitaj_znak() else {
|
||||||
|
println!("Neplatný vstup");
|
||||||
|
continue;
|
||||||
|
};
|
||||||
|
|
||||||
|
if !skusane.insert(pismeno) {
|
||||||
|
println!("Už si skúšal!");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if slovo.contains(pismeno) {
|
||||||
|
uhadnute.insert(pismeno);
|
||||||
|
println!("Správne!");
|
||||||
|
} else {
|
||||||
|
zivoty -= 1;
|
||||||
|
println!("Zle!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Úlohy 8
|
||||||
|
|
||||||
|
**8a.** Napíš "hádaj číslo" s obtiažnosťou: ľahká (1–10), stredná (1–50), ťažká (1–100).
|
||||||
|
|
||||||
|
**8b.** Napíš kvízovú hru: 5 otázok z náhodne zamiešaného poolu, hráč zadáva číslo odpovede.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Kapitola 9: Náhodné z HashMap a HashSet
|
||||||
|
|
||||||
|
Pre iterátory (nie slice) treba `IteratorRandom`:
|
||||||
|
|
||||||
|
```rust
|
||||||
|
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::rng();
|
||||||
|
|
||||||
|
// Náhodný kľúč
|
||||||
|
let kluc = mapa.keys().choose(&mut rng);
|
||||||
|
// Some(&"b")
|
||||||
|
|
||||||
|
// Náhodný pár
|
||||||
|
let par = mapa.iter().choose(&mut rng);
|
||||||
|
// Some((&"a", &1))
|
||||||
|
```
|
||||||
|
|
||||||
|
```rust
|
||||||
|
// HashSet — rovnako
|
||||||
|
use rand::seq::IteratorRandom;
|
||||||
|
|
||||||
|
let mnozina: HashSet<String> = vec!["pes", "mačka", "kôň"]
|
||||||
|
.into_iter().map(String::from).collect();
|
||||||
|
|
||||||
|
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, potom náhodné slovo z nej.
|
||||||
|
|
||||||
|
**9b.** Máš HashSet<char> 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::IndexedRandom;
|
||||||
|
use serde::{Serialize, Deserialize};
|
||||||
|
use std::collections::HashMap;
|
||||||
|
use std::path::PathBuf;
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Default)]
|
||||||
|
pub struct SpravcaHry {
|
||||||
|
pub slovnik: HashMap<String, Vec<String>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SpravcaHry {
|
||||||
|
pub fn nacitaj_zo_suboru(cesta: &PathBuf) -> Option<SpravcaHry> {
|
||||||
|
let raw = std::fs::read_to_string(cesta).ok()?;
|
||||||
|
serde_json::from_str(&raw).ok()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn uloz_do_suboru(&self, cesta: &PathBuf) -> bool {
|
||||||
|
let Ok(json) = serde_json::to_string_pretty(&self) else {
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
std::fs::write(cesta, json).is_ok()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn vytvor_novu_hru(&self, kategoria: &str) -> Option<Hra> {
|
||||||
|
let slova = self.slovnik.get(kategoria)?;
|
||||||
|
if slova.is_empty() {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
let mut rng = rand::rng();
|
||||||
|
let slovo = slova.choose(&mut rng)?;
|
||||||
|
Some(Hra::new(slovo))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn pridaj_kategoriu(&mut self, kategoria: &str) -> Result<(), ()> {
|
||||||
|
if self.slovnik.contains_key(kategoria) {
|
||||||
|
return Err(());
|
||||||
|
}
|
||||||
|
self.slovnik.insert(kategoria.to_string(), Vec::new());
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn pridaj_slovo(&mut self, kategoria: &str, slovo: &str) -> Result<(), ()> {
|
||||||
|
let slova = self.slovnik.get_mut(kategoria).ok_or(())?;
|
||||||
|
slova.push(slovo.to_string());
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### main.rs s clapom
|
||||||
|
|
||||||
|
```rust
|
||||||
|
use clap::{Parser, Subcommand};
|
||||||
|
use std::path::PathBuf;
|
||||||
|
|
||||||
|
#[derive(Parser)]
|
||||||
|
struct Args {
|
||||||
|
#[command(subcommand)]
|
||||||
|
cmd: Cmd,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Subcommand)]
|
||||||
|
enum Cmd {
|
||||||
|
PridajKategoriu {
|
||||||
|
cesta: PathBuf,
|
||||||
|
kategoria: String,
|
||||||
|
},
|
||||||
|
PridajSlovo {
|
||||||
|
cesta: PathBuf,
|
||||||
|
kategoria: String,
|
||||||
|
slovo: String,
|
||||||
|
},
|
||||||
|
Hraj {
|
||||||
|
cesta: PathBuf,
|
||||||
|
kategoria: String,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let args = Args::parse();
|
||||||
|
|
||||||
|
match args.cmd {
|
||||||
|
Cmd::PridajKategoriu { cesta, kategoria } => {
|
||||||
|
let mut spravca = SpravcaHry::nacitaj_zo_suboru(&cesta)
|
||||||
|
.unwrap_or_default();
|
||||||
|
match spravca.pridaj_kategoriu(&kategoria) {
|
||||||
|
Ok(()) => {
|
||||||
|
spravca.uloz_do_suboru(&cesta);
|
||||||
|
println!("Kategória pridaná.");
|
||||||
|
}
|
||||||
|
Err(()) => println!("Kategória už existuje."),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Cmd::PridajSlovo { cesta, kategoria, slovo } => {
|
||||||
|
let mut spravca = SpravcaHry::nacitaj_zo_suboru(&cesta)
|
||||||
|
.unwrap_or_default();
|
||||||
|
match spravca.pridaj_slovo(&kategoria, &slovo) {
|
||||||
|
Ok(()) => {
|
||||||
|
spravca.uloz_do_suboru(&cesta);
|
||||||
|
println!("Slovo pridané.");
|
||||||
|
}
|
||||||
|
Err(()) => println!("Kategória neexistuje."),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Cmd::Hraj { cesta, kategoria } => {
|
||||||
|
let spravca = SpravcaHry::nacitaj_zo_suboru(&cesta)
|
||||||
|
.unwrap_or_default();
|
||||||
|
match spravca.vytvor_novu_hru(&kategoria) {
|
||||||
|
Some(mut hra) => {
|
||||||
|
hra.hraj(ConsoleIOManager);
|
||||||
|
}
|
||||||
|
None => println!("Kategória neexistuje alebo je prázdna."),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Úlohy 10
|
||||||
|
|
||||||
|
**10a.** Napíš celý SpravcaHry od nuly bez pozerania.
|
||||||
|
|
||||||
|
**10b.** Napíš main.rs s clapom bez pozerania.
|
||||||
|
|
||||||
|
**10c.** Rozšír o metódu `nahodna_kategoria(&self) -> Option<&String>`. Použi `IteratorRandom`.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Prehľad: čo importovať a kedy
|
||||||
|
|
||||||
|
| Chcem... | Import | Metóda |
|
||||||
|
|----------|--------|--------|
|
||||||
|
| 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 | `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::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;` |
|
||||||
298
priprava/rust_priprava15.md
Normal file
298
priprava/rust_priprava15.md
Normal file
@@ -0,0 +1,298 @@
|
|||||||
|
# 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é".
|
||||||
|
|
||||||
|
```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<T, ()>
|
||||||
|
|
||||||
|
Keď pri úspechu vraciaš niečo, ale chyba nemá detail:
|
||||||
|
|
||||||
|
```rust
|
||||||
|
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:
|
||||||
|
|
||||||
|
```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<T, E> → .ok() → Option<T>
|
||||||
|
|
||||||
|
Ok(42) → .ok() → Some(42)
|
||||||
|
Err("chyba") → .ok() → None
|
||||||
|
```
|
||||||
|
|
||||||
|
```rust
|
||||||
|
// 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:
|
||||||
|
|
||||||
|
```rust
|
||||||
|
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
|
||||||
|
|
||||||
|
```rust
|
||||||
|
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:**
|
||||||
|
|
||||||
|
```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<T> → .ok_or(chyba) → Result<T, E>
|
||||||
|
|
||||||
|
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<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))
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
```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<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íď
|
||||||
|
|
||||||
|
```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<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)
|
||||||
|
```
|
||||||
298
priprava/rust_priprava16.md
Normal file
298
priprava/rust_priprava16.md
Normal file
@@ -0,0 +1,298 @@
|
|||||||
|
# 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é".
|
||||||
|
|
||||||
|
```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<T, ()>
|
||||||
|
|
||||||
|
Keď pri úspechu vraciaš niečo, ale chyba nemá detail:
|
||||||
|
|
||||||
|
```rust
|
||||||
|
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:
|
||||||
|
|
||||||
|
```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<T, E> → .ok() → Option<T>
|
||||||
|
|
||||||
|
Ok(42) → .ok() → Some(42)
|
||||||
|
Err("chyba") → .ok() → None
|
||||||
|
```
|
||||||
|
|
||||||
|
```rust
|
||||||
|
// 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:
|
||||||
|
|
||||||
|
```rust
|
||||||
|
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
|
||||||
|
|
||||||
|
```rust
|
||||||
|
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:**
|
||||||
|
|
||||||
|
```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<T> → .ok_or(chyba) → Result<T, E>
|
||||||
|
|
||||||
|
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<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))
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
```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<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íď
|
||||||
|
|
||||||
|
```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<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)
|
||||||
|
```
|
||||||
1119
priprava/rust_priprava3.md
Normal file
1119
priprava/rust_priprava3.md
Normal file
File diff suppressed because it is too large
Load Diff
762
priprava/rust_priprava4.md
Normal file
762
priprava/rust_priprava4.md
Normal file
@@ -0,0 +1,762 @@
|
|||||||
|
# HashMap — krok za krokom
|
||||||
|
|
||||||
|
Každá kapitola: prečítaj, pozri príklady, urob úlohy. Až potom choď ďalej.
|
||||||
|
Riešenia sú na konci, číslované.
|
||||||
|
|
||||||
|
```rust
|
||||||
|
use std::collections::HashMap; // toto treba vždy
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Kapitola 1: Vytvorenie a insert
|
||||||
|
|
||||||
|
HashMap je kolekcia párov kľúč → hodnota. Kľúč je unikátny.
|
||||||
|
|
||||||
|
```rust
|
||||||
|
let mut mapa: HashMap<String, i32> = HashMap::new();
|
||||||
|
|
||||||
|
mapa.insert("Anna".to_string(), 25);
|
||||||
|
mapa.insert("Boris".to_string(), 30);
|
||||||
|
// mapa = {"Anna": 25, "Boris": 30}
|
||||||
|
|
||||||
|
// insert na existujúci kľúč PREPÍŠE hodnotu a vráti starú
|
||||||
|
let stara = mapa.insert("Anna".to_string(), 26);
|
||||||
|
// stara = Some(25), mapa = {"Anna": 26, "Boris": 30}
|
||||||
|
|
||||||
|
// insert na nový kľúč vráti None
|
||||||
|
let stara = mapa.insert("Cyril".to_string(), 22);
|
||||||
|
// stara = None
|
||||||
|
```
|
||||||
|
|
||||||
|
### Úlohy 1
|
||||||
|
|
||||||
|
**1a.** Vytvor HashMap kde kľúče sú mená ovocia (String) a hodnoty sú ceny (f64). Vlož 3 ovocia.
|
||||||
|
|
||||||
|
**1b.** Čo vráti posledný insert? Napíš kód a over:
|
||||||
|
```rust
|
||||||
|
let mut m = HashMap::new();
|
||||||
|
m.insert("x", 1);
|
||||||
|
m.insert("y", 2);
|
||||||
|
let vysledok = m.insert("x", 99);
|
||||||
|
println!("{:?}", vysledok);
|
||||||
|
```
|
||||||
|
|
||||||
|
**1c.** Vytvor HashMap z vektora dvojíc pomocou `.collect()`:
|
||||||
|
```rust
|
||||||
|
let data = vec![("sk", "Slovensko"), ("cz", "Česko"), ("pl", "Poľsko")];
|
||||||
|
// tvoj kód → HashMap<&str, &str>
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Kapitola 2: Čítanie — get, contains_key, len
|
||||||
|
|
||||||
|
```rust
|
||||||
|
let mut mapa = HashMap::new();
|
||||||
|
mapa.insert("Anna".to_string(), 25);
|
||||||
|
mapa.insert("Boris".to_string(), 30);
|
||||||
|
|
||||||
|
// get — vráti Option<&V>
|
||||||
|
let vek = mapa.get("Anna"); // Some(&25)
|
||||||
|
let vek = mapa.get("Cyril"); // None
|
||||||
|
|
||||||
|
// contains_key — vráti bool
|
||||||
|
let je_tam = mapa.contains_key("Anna"); // true
|
||||||
|
let je_tam = mapa.contains_key("Cyril"); // false
|
||||||
|
|
||||||
|
// len — počet párov
|
||||||
|
let pocet = mapa.len(); // 2
|
||||||
|
|
||||||
|
// is_empty
|
||||||
|
let prazdna = mapa.is_empty(); // false
|
||||||
|
```
|
||||||
|
|
||||||
|
**Dôležité:** Nikdy nepoužívaj `mapa["Anna"]` — ak kľúč neexistuje, program spadne. Vždy `.get()`.
|
||||||
|
|
||||||
|
### Úlohy 2
|
||||||
|
|
||||||
|
**2a.** Máš mapu ovocia z úlohy 1a. Napíš kód, ktorý:
|
||||||
|
- Vypíše cenu jablka ak existuje
|
||||||
|
- Vypíše "Nemáme" ak neexistuje
|
||||||
|
Použi `if let` s `.get()`.
|
||||||
|
|
||||||
|
**2b.** Napíš funkciu:
|
||||||
|
```rust
|
||||||
|
fn je_v_mape(mapa: &HashMap<String, i32>, kluc: &str) -> bool
|
||||||
|
```
|
||||||
|
Použi `contains_key`.
|
||||||
|
|
||||||
|
**2c.** Čo vypíše? Tipni, potom over:
|
||||||
|
```rust
|
||||||
|
let mut m: HashMap<&str, i32> = HashMap::new();
|
||||||
|
m.insert("a", 1);
|
||||||
|
println!("{:?}", m.get("a"));
|
||||||
|
println!("{:?}", m.get("b"));
|
||||||
|
println!("{}", m.len());
|
||||||
|
println!("{}", m.contains_key("a"));
|
||||||
|
println!("{}", m.contains_key("b"));
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Kapitola 3: Mazanie — remove, clear
|
||||||
|
|
||||||
|
```rust
|
||||||
|
let mut mapa = HashMap::new();
|
||||||
|
mapa.insert("Anna".to_string(), 25);
|
||||||
|
mapa.insert("Boris".to_string(), 30);
|
||||||
|
|
||||||
|
// remove — vráti Option<V> (hodnotu, nie referenciu)
|
||||||
|
let odstraneny = mapa.remove("Anna");
|
||||||
|
// odstraneny = Some(25), mapa = {"Boris": 30}
|
||||||
|
|
||||||
|
let odstraneny = mapa.remove("Cyril");
|
||||||
|
// odstraneny = None (neexistoval)
|
||||||
|
|
||||||
|
// clear — vymaže všetko
|
||||||
|
mapa.clear();
|
||||||
|
// mapa = {}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Úlohy 3
|
||||||
|
|
||||||
|
**3a.** Vytvor mapu s 3 položkami. Odstráň jednu. Vypíš čo `remove` vrátil. Vypíš veľkosť mapy.
|
||||||
|
|
||||||
|
**3b.** Napíš funkciu:
|
||||||
|
```rust
|
||||||
|
fn odstran_ak_existuje(mapa: &mut HashMap<String, i32>, kluc: &str) -> Option<i32>
|
||||||
|
```
|
||||||
|
Ak kľúč existuje, odstráň ho a vráť hodnotu. Ak nie, vráť None. (Hint: `remove` presne toto robí.)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Kapitola 4: Iterácia
|
||||||
|
|
||||||
|
```rust
|
||||||
|
let mut mapa = HashMap::new();
|
||||||
|
mapa.insert("Anna".to_string(), 25);
|
||||||
|
mapa.insert("Boris".to_string(), 30);
|
||||||
|
mapa.insert("Cyril".to_string(), 22);
|
||||||
|
|
||||||
|
// Cez páry — poradie NIE JE garantované!
|
||||||
|
for (meno, vek) in &mapa {
|
||||||
|
println!("{}: {}", meno, vek);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Len kľúče
|
||||||
|
for meno in mapa.keys() {
|
||||||
|
println!("{}", meno);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Len hodnoty
|
||||||
|
for vek in mapa.values() {
|
||||||
|
println!("{}", vek);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Meniteľné hodnoty
|
||||||
|
for vek in mapa.values_mut() {
|
||||||
|
*vek += 1;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Úlohy 4
|
||||||
|
|
||||||
|
**4a.** Vytvor mapu produktov (názov → cena). Vypíš všetky produkty vo formáte `"Produkt: cena €"`.
|
||||||
|
|
||||||
|
**4b.** Napíš funkciu, ktorá vráti vektor všetkých kľúčov z mapy:
|
||||||
|
```rust
|
||||||
|
fn kluce(mapa: &HashMap<String, i32>) -> Vec<&String>
|
||||||
|
```
|
||||||
|
|
||||||
|
**4c.** Napíš funkciu, ktorá zvýši všetky hodnoty v mape o 10:
|
||||||
|
```rust
|
||||||
|
fn zvys_vsetky(mapa: &mut HashMap<String, i32>)
|
||||||
|
```
|
||||||
|
|
||||||
|
**4d.** Napíš funkciu, ktorá vráti súčet všetkých hodnôt:
|
||||||
|
```rust
|
||||||
|
fn sucet_hodnot(mapa: &HashMap<String, i32>) -> i32
|
||||||
|
```
|
||||||
|
Použi `.values()` a `.sum()`.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Kapitola 5: get_mut — zmena hodnoty na mieste
|
||||||
|
|
||||||
|
Ak chceš zmeniť jednu konkrétnu hodnotu (nie všetky), použi `get_mut`:
|
||||||
|
|
||||||
|
```rust
|
||||||
|
let mut mapa = HashMap::new();
|
||||||
|
mapa.insert("Anna".to_string(), 25);
|
||||||
|
|
||||||
|
// get_mut vráti Option<&mut V>
|
||||||
|
if let Some(vek) = mapa.get_mut("Anna") {
|
||||||
|
*vek += 1; // Anna má teraz 26
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ak kľúč neexistuje, get_mut vráti None
|
||||||
|
if let Some(vek) = mapa.get_mut("Boris") {
|
||||||
|
*vek += 1; // Toto sa nevykoná
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Úlohy 5
|
||||||
|
|
||||||
|
**5a.** Máš mapu študentov (meno → počet bodov). Napíš funkciu, ktorá pridá body jednému študentovi:
|
||||||
|
```rust
|
||||||
|
fn pridaj_body(mapa: &mut HashMap<String, u32>, meno: &str, body: u32) -> bool
|
||||||
|
```
|
||||||
|
Vráti `true` ak študent existoval, `false` ak nie.
|
||||||
|
|
||||||
|
**5b.** Napíš funkciu, ktorá zdvojnásobí hodnotu pre daný kľúč:
|
||||||
|
```rust
|
||||||
|
fn zdvojnasob(mapa: &mut HashMap<String, i32>, kluc: &str) -> Option<i32>
|
||||||
|
```
|
||||||
|
Vráti novú hodnotu ak kľúč existoval, None ak nie.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Kapitola 6: Entry API — or_insert
|
||||||
|
|
||||||
|
Toto je najdôležitejšia časť. Entry API rieši situáciu: "ak kľúč neexistuje, vlož default; ak existuje, použi existujúcu hodnotu."
|
||||||
|
|
||||||
|
```rust
|
||||||
|
let mut mapa: HashMap<String, i32> = HashMap::new();
|
||||||
|
|
||||||
|
// entry() vráti Entry — buď Vacant (prázdny) alebo Occupied (obsadený)
|
||||||
|
// or_insert(hodnota) — ak Vacant, vlož hodnotu. Vráti &mut na hodnotu.
|
||||||
|
|
||||||
|
mapa.entry("Anna".to_string()).or_insert(25);
|
||||||
|
// Anna neexistovala → vloží 25 → mapa = {"Anna": 25}
|
||||||
|
|
||||||
|
mapa.entry("Anna".to_string()).or_insert(99);
|
||||||
|
// Anna existuje → NEVLOŽÍ 99 → mapa = {"Anna": 25} (nezmenené!)
|
||||||
|
```
|
||||||
|
|
||||||
|
**Hlavné použitie — počítanie výskytov:**
|
||||||
|
|
||||||
|
```rust
|
||||||
|
let slova = vec!["ahoj", "svet", "ahoj", "rust", "svet", "ahoj"];
|
||||||
|
let mut pocty: HashMap<String, usize> = HashMap::new();
|
||||||
|
|
||||||
|
for slovo in &slova {
|
||||||
|
*pocty.entry(slovo.to_string()).or_insert(0) += 1;
|
||||||
|
}
|
||||||
|
// {"ahoj": 3, "svet": 2, "rust": 1}
|
||||||
|
```
|
||||||
|
|
||||||
|
Čo sa deje krok po kroku:
|
||||||
|
```
|
||||||
|
Slovo "ahoj":
|
||||||
|
entry("ahoj") → Vacant → or_insert(0) vloží 0 → vráti &mut 0
|
||||||
|
*(&mut 0) += 1 → hodnota je 1
|
||||||
|
|
||||||
|
Slovo "svet":
|
||||||
|
entry("svet") → Vacant → or_insert(0) vloží 0 → vráti &mut 0
|
||||||
|
*(&mut 0) += 1 → hodnota je 1
|
||||||
|
|
||||||
|
Slovo "ahoj" (druhýkrát):
|
||||||
|
entry("ahoj") → Occupied (hodnota 1) → or_insert(0) NEVLOŽÍ → vráti &mut 1
|
||||||
|
*(&mut 1) += 1 → hodnota je 2
|
||||||
|
```
|
||||||
|
|
||||||
|
### Úlohy 6
|
||||||
|
|
||||||
|
**6a.** Spočítaj výskyt každého znaku v reťazci `"abrakadabra"`. Použi `entry` + `or_insert`. Výsledok vypíš.
|
||||||
|
|
||||||
|
**6b.** Máš vektor čísel `[1, 3, 2, 1, 4, 3, 2, 1, 5]`. Spočítaj koľkokrát sa vyskytuje každé číslo.
|
||||||
|
|
||||||
|
**6c.** Čo vypíše? Tipni, potom over:
|
||||||
|
```rust
|
||||||
|
let mut m: HashMap<&str, i32> = HashMap::new();
|
||||||
|
m.entry("a").or_insert(10);
|
||||||
|
m.entry("b").or_insert(20);
|
||||||
|
m.entry("a").or_insert(99);
|
||||||
|
m.insert("b", 99);
|
||||||
|
println!("{:?}", m.get("a"));
|
||||||
|
println!("{:?}", m.get("b"));
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Kapitola 7: Entry API — or_default
|
||||||
|
|
||||||
|
`or_default()` je skratka za `or_insert(Default::default())`. Vloží defaultnú hodnotu pre daný typ.
|
||||||
|
|
||||||
|
| Typ | Default |
|
||||||
|
|-----|---------|
|
||||||
|
| usize, i32, u32... | 0 |
|
||||||
|
| f64 | 0.0 |
|
||||||
|
| bool | false |
|
||||||
|
| String | "" |
|
||||||
|
| Vec<T> | vec![] |
|
||||||
|
|
||||||
|
```rust
|
||||||
|
let mut pocty: HashMap<String, usize> = HashMap::new();
|
||||||
|
|
||||||
|
// Tieto dva riadky robia to isté:
|
||||||
|
*pocty.entry("ahoj".to_string()).or_insert(0) += 1;
|
||||||
|
*pocty.entry("ahoj".to_string()).or_default() += 1;
|
||||||
|
```
|
||||||
|
|
||||||
|
**Hlavné použitie — zoskupovanie do vektorov:**
|
||||||
|
|
||||||
|
```rust
|
||||||
|
let mut skupiny: HashMap<String, Vec<String>> = HashMap::new();
|
||||||
|
|
||||||
|
// or_default() pre Vec vloží prázdny vektor
|
||||||
|
skupiny.entry("ovocie".to_string()).or_default().push("jablko".to_string());
|
||||||
|
skupiny.entry("ovocie".to_string()).or_default().push("hruška".to_string());
|
||||||
|
skupiny.entry("zelenina".to_string()).or_default().push("mrkva".to_string());
|
||||||
|
// {"ovocie": ["jablko", "hruška"], "zelenina": ["mrkva"]}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Úlohy 7
|
||||||
|
|
||||||
|
**7a.** Máš vektor slov. Zoskup ich podľa prvého písmena do HashMap<char, Vec<String>>:
|
||||||
|
```rust
|
||||||
|
let slova = vec!["auto", "ahoj", "banán", "breza", "citrón", "auto"];
|
||||||
|
// Výsledok: {'a': ["auto", "ahoj", "auto"], 'b': ["banán", "breza"], 'c': ["citrón"]}
|
||||||
|
```
|
||||||
|
|
||||||
|
**7b.** Máš vektor dvojíc (študent, predmet). Zoskup predmety podľa študenta:
|
||||||
|
```rust
|
||||||
|
let data = vec![
|
||||||
|
("Anna", "Matematika"),
|
||||||
|
("Boris", "Fyzika"),
|
||||||
|
("Anna", "Fyzika"),
|
||||||
|
("Boris", "Chémia"),
|
||||||
|
("Anna", "Chémia"),
|
||||||
|
];
|
||||||
|
// Výsledok: {"Anna": ["Matematika", "Fyzika", "Chémia"], "Boris": ["Fyzika", "Chémia"]}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Kapitola 8: Entry API — and_modify
|
||||||
|
|
||||||
|
`and_modify` ti umožní spraviť niečo s existujúcou hodnotou pred tým, ako sa rozhodne čo robiť:
|
||||||
|
|
||||||
|
```rust
|
||||||
|
let mut mapa: HashMap<String, i32> = HashMap::new();
|
||||||
|
|
||||||
|
// Ak existuje → zvýš o 1. Ak neexistuje → vlož 1.
|
||||||
|
mapa.entry("Anna".to_string())
|
||||||
|
.and_modify(|v| *v += 1)
|
||||||
|
.or_insert(1);
|
||||||
|
// Anna neexistovala → vloží 1
|
||||||
|
|
||||||
|
mapa.entry("Anna".to_string())
|
||||||
|
.and_modify(|v| *v += 1)
|
||||||
|
.or_insert(1);
|
||||||
|
// Anna existuje s hodnotou 1 → and_modify zvýši na 2
|
||||||
|
```
|
||||||
|
|
||||||
|
Toto je užitočné keď chceš robiť rôzne veci pre nový vs existujúci kľúč.
|
||||||
|
|
||||||
|
### Úlohy 8
|
||||||
|
|
||||||
|
**8a.** Máš vektor mien. Pre každé meno: ak sa vyskytlo prvýkrát, vlož `1`. Ak sa vyskytlo znovu, zvýš o `1`. Použi `and_modify` + `or_insert`. (Áno, výsledok je rovnaký ako cez `or_insert(0) += 1`, ale precvič si syntax.)
|
||||||
|
|
||||||
|
**8b.** Máš mapu produktov (String → (cena: f64, počet: u32)). Napíš kód, ktorý: ak produkt existuje, zvýši počet o 1. Ak neexistuje, vloží ho s cenou 10.0 a počtom 1.
|
||||||
|
```rust
|
||||||
|
let mut produkty: HashMap<String, (f64, u32)> = HashMap::new();
|
||||||
|
// tvoj kód pre produkt "mlieko"
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Kapitola 9: Iterátory s HashMap
|
||||||
|
|
||||||
|
HashMap sa dá kombinovať s iterátorovými metódami:
|
||||||
|
|
||||||
|
```rust
|
||||||
|
let mut mapa = HashMap::new();
|
||||||
|
mapa.insert("Anna".to_string(), 25);
|
||||||
|
mapa.insert("Boris".to_string(), 30);
|
||||||
|
mapa.insert("Cyril".to_string(), 17);
|
||||||
|
|
||||||
|
// filter — nechaj len dospelých
|
||||||
|
let dospeli: HashMap<&String, &i32> = mapa.iter()
|
||||||
|
.filter(|(_, vek)| **vek >= 18)
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
// find — nájdi prvého s daným menom
|
||||||
|
let boris: Option<(&String, &i32)> = mapa.iter()
|
||||||
|
.find(|(meno, _)| meno.as_str() == "Boris");
|
||||||
|
|
||||||
|
// max_by_key — najstarší
|
||||||
|
let najstarsi: Option<(&String, &i32)> = mapa.iter()
|
||||||
|
.max_by_key(|(_, vek)| *vek);
|
||||||
|
|
||||||
|
// Kľúče do Vec
|
||||||
|
let mena: Vec<&String> = mapa.keys().collect();
|
||||||
|
|
||||||
|
// Hodnoty — súčet
|
||||||
|
let sucet_vekov: i32 = mapa.values().sum();
|
||||||
|
```
|
||||||
|
|
||||||
|
### Úlohy 9
|
||||||
|
|
||||||
|
**9a.** Máš `HashMap<String, f64>` (produkt → cena). Nájdi najdrahší produkt. Vráť jeho názov ako `Option<&String>`.
|
||||||
|
|
||||||
|
**9b.** Máš `HashMap<String, u32>` (mesto → populácia). Vráť Vec miest s populáciou nad 100_000.
|
||||||
|
|
||||||
|
**9c.** Máš `HashMap<String, Vec<String>>` (kategória → produkty). Nájdi celkový počet produktov naprieč všetkými kategóriami. Použi `.values()` a `.map()` a `.sum()`.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Kapitola 10: Praktické vzory zo skúšky
|
||||||
|
|
||||||
|
### Vzor 1: Počítanie podľa poľa štruktúry
|
||||||
|
|
||||||
|
```rust
|
||||||
|
struct Kniha { nazov: String, vydavatelstvo: String }
|
||||||
|
|
||||||
|
fn pocty_podla_vydavatelstva(knihy: &[Kniha]) -> HashMap<String, usize> {
|
||||||
|
let mut mapa = HashMap::new();
|
||||||
|
for kniha in knihy {
|
||||||
|
*mapa.entry(kniha.vydavatelstvo.clone()).or_insert(0) += 1;
|
||||||
|
}
|
||||||
|
mapa
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Vzor 2: Výpis vo formáte "Kľúč: hodnota"
|
||||||
|
|
||||||
|
```rust
|
||||||
|
fn vypis_statistiky(knihy: &[Kniha]) {
|
||||||
|
let pocty = pocty_podla_vydavatelstva(knihy);
|
||||||
|
for (vydavatelstvo, pocet) in &pocty {
|
||||||
|
println!("{}: {}", vydavatelstvo, pocet);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Vzor 3: Nájdi najčastejší
|
||||||
|
|
||||||
|
```rust
|
||||||
|
fn najcastejsie_vydavatelstvo(knihy: &[Kniha]) -> Option<String> {
|
||||||
|
let pocty = pocty_podla_vydavatelstva(knihy);
|
||||||
|
pocty.into_iter()
|
||||||
|
.max_by_key(|(_, pocet)| *pocet)
|
||||||
|
.map(|(vydavatelstvo, _)| vydavatelstvo)
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Úlohy 10
|
||||||
|
|
||||||
|
**10a.** Máš:
|
||||||
|
```rust
|
||||||
|
struct Zamestnanec { meno: String, oddelenie: String, plat: u32 }
|
||||||
|
```
|
||||||
|
Napíš funkciu `pocet_na_oddeleni(zamestnanci: &[Zamestnanec]) -> HashMap<String, usize>`.
|
||||||
|
|
||||||
|
**10b.** Napíš funkciu `celkovy_plat_na_oddeleni(zamestnanci: &[Zamestnanec]) -> HashMap<String, u32>` — súčet platov na každom oddelení.
|
||||||
|
|
||||||
|
**10c.** Napíš funkciu `vypis_statistiky(zamestnanci: &[Zamestnanec])` — pre každé oddelenie vypíše počet ľudí a celkový plat.
|
||||||
|
|
||||||
|
**10d.** Napíš funkciu `oddelenie_s_najvyssim_platom(zamestnanci: &[Zamestnanec]) -> Option<String>` — oddelenie kde je najväčší celkový plat.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# RIEŠENIA
|
||||||
|
|
||||||
|
## 1a
|
||||||
|
|
||||||
|
```rust
|
||||||
|
let mut ovocie: HashMap<String, f64> = HashMap::new();
|
||||||
|
ovocie.insert("Jablko".to_string(), 1.50);
|
||||||
|
ovocie.insert("Banán".to_string(), 2.00);
|
||||||
|
ovocie.insert("Pomaranč".to_string(), 2.50);
|
||||||
|
```
|
||||||
|
|
||||||
|
## 1b
|
||||||
|
|
||||||
|
```
|
||||||
|
Some(1)
|
||||||
|
```
|
||||||
|
Lebo `"x"` už existoval s hodnotou 1, `insert` ho prepísal na 99 a vrátil starú hodnotu.
|
||||||
|
|
||||||
|
## 1c
|
||||||
|
|
||||||
|
```rust
|
||||||
|
let data = vec![("sk", "Slovensko"), ("cz", "Česko"), ("pl", "Poľsko")];
|
||||||
|
let mapa: HashMap<&str, &str> = data.into_iter().collect();
|
||||||
|
```
|
||||||
|
|
||||||
|
## 2a
|
||||||
|
|
||||||
|
```rust
|
||||||
|
if let Some(cena) = ovocie.get("Jablko") {
|
||||||
|
println!("Cena: {} €", cena);
|
||||||
|
} else {
|
||||||
|
println!("Nemáme");
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 2b
|
||||||
|
|
||||||
|
```rust
|
||||||
|
fn je_v_mape(mapa: &HashMap<String, i32>, kluc: &str) -> bool {
|
||||||
|
mapa.contains_key(kluc)
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 2c
|
||||||
|
|
||||||
|
```
|
||||||
|
Some(1)
|
||||||
|
None
|
||||||
|
1
|
||||||
|
true
|
||||||
|
false
|
||||||
|
```
|
||||||
|
|
||||||
|
## 3a
|
||||||
|
|
||||||
|
```rust
|
||||||
|
let mut mapa = HashMap::new();
|
||||||
|
mapa.insert("A".to_string(), 1);
|
||||||
|
mapa.insert("B".to_string(), 2);
|
||||||
|
mapa.insert("C".to_string(), 3);
|
||||||
|
|
||||||
|
let odstraneny = mapa.remove("B");
|
||||||
|
println!("{:?}", odstraneny); // Some(2)
|
||||||
|
println!("{}", mapa.len()); // 2
|
||||||
|
```
|
||||||
|
|
||||||
|
## 3b
|
||||||
|
|
||||||
|
```rust
|
||||||
|
fn odstran_ak_existuje(mapa: &mut HashMap<String, i32>, kluc: &str) -> Option<i32> {
|
||||||
|
mapa.remove(kluc)
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 4a
|
||||||
|
|
||||||
|
```rust
|
||||||
|
let mut produkty = HashMap::new();
|
||||||
|
produkty.insert("Chlieb".to_string(), 1.20);
|
||||||
|
produkty.insert("Mlieko".to_string(), 0.89);
|
||||||
|
produkty.insert("Maslo".to_string(), 2.50);
|
||||||
|
|
||||||
|
for (nazov, cena) in &produkty {
|
||||||
|
println!("{}: {} €", nazov, cena);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 4b
|
||||||
|
|
||||||
|
```rust
|
||||||
|
fn kluce(mapa: &HashMap<String, i32>) -> Vec<&String> {
|
||||||
|
mapa.keys().collect()
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 4c
|
||||||
|
|
||||||
|
```rust
|
||||||
|
fn zvys_vsetky(mapa: &mut HashMap<String, i32>) {
|
||||||
|
for hodnota in mapa.values_mut() {
|
||||||
|
*hodnota += 10;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 4d
|
||||||
|
|
||||||
|
```rust
|
||||||
|
fn sucet_hodnot(mapa: &HashMap<String, i32>) -> i32 {
|
||||||
|
mapa.values().sum()
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 5a
|
||||||
|
|
||||||
|
```rust
|
||||||
|
fn pridaj_body(mapa: &mut HashMap<String, u32>, meno: &str, body: u32) -> bool {
|
||||||
|
if let Some(aktualne) = mapa.get_mut(meno) {
|
||||||
|
*aktualne += body;
|
||||||
|
true
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 5b
|
||||||
|
|
||||||
|
```rust
|
||||||
|
fn zdvojnasob(mapa: &mut HashMap<String, i32>, kluc: &str) -> Option<i32> {
|
||||||
|
let hodnota = mapa.get_mut(kluc)?;
|
||||||
|
*hodnota *= 2;
|
||||||
|
Some(*hodnota)
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 6a
|
||||||
|
|
||||||
|
```rust
|
||||||
|
let text = "abrakadabra";
|
||||||
|
let mut pocty: HashMap<char, usize> = HashMap::new();
|
||||||
|
for c in text.chars() {
|
||||||
|
*pocty.entry(c).or_insert(0) += 1;
|
||||||
|
}
|
||||||
|
for (znak, pocet) in &pocty {
|
||||||
|
println!("{}: {}", znak, pocet);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 6b
|
||||||
|
|
||||||
|
```rust
|
||||||
|
let cisla = vec![1, 3, 2, 1, 4, 3, 2, 1, 5];
|
||||||
|
let mut pocty: HashMap<i32, usize> = HashMap::new();
|
||||||
|
for c in &cisla {
|
||||||
|
*pocty.entry(*c).or_insert(0) += 1;
|
||||||
|
}
|
||||||
|
// {1: 3, 3: 2, 2: 2, 4: 1, 5: 1}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 6c
|
||||||
|
|
||||||
|
```
|
||||||
|
Some(10)
|
||||||
|
Some(99)
|
||||||
|
```
|
||||||
|
`entry("a").or_insert(99)` — "a" už existuje, takže 99 sa NEVLOŽÍ, ostáva 10.
|
||||||
|
`insert("b", 99)` — insert VŽDY prepíše, takže "b" je teraz 99.
|
||||||
|
|
||||||
|
## 7a
|
||||||
|
|
||||||
|
```rust
|
||||||
|
let slova = vec!["auto", "ahoj", "banán", "breza", "citrón", "auto"];
|
||||||
|
let mut skupiny: HashMap<char, Vec<String>> = HashMap::new();
|
||||||
|
for slovo in &slova {
|
||||||
|
if let Some(prvy) = slovo.chars().next() {
|
||||||
|
skupiny.entry(prvy).or_default().push(slovo.to_string());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 7b
|
||||||
|
|
||||||
|
```rust
|
||||||
|
let data = vec![
|
||||||
|
("Anna", "Matematika"),
|
||||||
|
("Boris", "Fyzika"),
|
||||||
|
("Anna", "Fyzika"),
|
||||||
|
("Boris", "Chémia"),
|
||||||
|
("Anna", "Chémia"),
|
||||||
|
];
|
||||||
|
let mut mapa: HashMap<String, Vec<String>> = HashMap::new();
|
||||||
|
for (student, predmet) in &data {
|
||||||
|
mapa.entry(student.to_string()).or_default().push(predmet.to_string());
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 8a
|
||||||
|
|
||||||
|
```rust
|
||||||
|
let mena = vec!["Anna", "Boris", "Anna", "Cyril", "Boris", "Anna"];
|
||||||
|
let mut pocty: HashMap<String, i32> = HashMap::new();
|
||||||
|
for meno in &mena {
|
||||||
|
pocty.entry(meno.to_string())
|
||||||
|
.and_modify(|v| *v += 1)
|
||||||
|
.or_insert(1);
|
||||||
|
}
|
||||||
|
// {"Anna": 3, "Boris": 2, "Cyril": 1}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 8b
|
||||||
|
|
||||||
|
```rust
|
||||||
|
let mut produkty: HashMap<String, (f64, u32)> = HashMap::new();
|
||||||
|
produkty.entry("mlieko".to_string())
|
||||||
|
.and_modify(|(_, pocet)| *pocet += 1)
|
||||||
|
.or_insert((10.0, 1));
|
||||||
|
```
|
||||||
|
|
||||||
|
## 9a
|
||||||
|
|
||||||
|
```rust
|
||||||
|
fn najdrahsi(mapa: &HashMap<String, f64>) -> Option<&String> {
|
||||||
|
mapa.iter()
|
||||||
|
.max_by(|(_, a), (_, b)| a.partial_cmp(b).unwrap())
|
||||||
|
.map(|(nazov, _)| nazov)
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 9b
|
||||||
|
|
||||||
|
```rust
|
||||||
|
fn velke_mesta(mapa: &HashMap<String, u32>) -> Vec<&String> {
|
||||||
|
mapa.iter()
|
||||||
|
.filter(|(_, pop)| **pop > 100_000)
|
||||||
|
.map(|(mesto, _)| mesto)
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 9c
|
||||||
|
|
||||||
|
```rust
|
||||||
|
fn celkovy_pocet(mapa: &HashMap<String, Vec<String>>) -> usize {
|
||||||
|
mapa.values().map(|v| v.len()).sum()
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 10a
|
||||||
|
|
||||||
|
```rust
|
||||||
|
fn pocet_na_oddeleni(zamestnanci: &[Zamestnanec]) -> HashMap<String, usize> {
|
||||||
|
let mut mapa = HashMap::new();
|
||||||
|
for z in zamestnanci {
|
||||||
|
*mapa.entry(z.oddelenie.clone()).or_insert(0) += 1;
|
||||||
|
}
|
||||||
|
mapa
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 10b
|
||||||
|
|
||||||
|
```rust
|
||||||
|
fn celkovy_plat_na_oddeleni(zamestnanci: &[Zamestnanec]) -> HashMap<String, u32> {
|
||||||
|
let mut mapa: HashMap<String, u32> = HashMap::new();
|
||||||
|
for z in zamestnanci {
|
||||||
|
*mapa.entry(z.oddelenie.clone()).or_insert(0) += z.plat;
|
||||||
|
}
|
||||||
|
mapa
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 10c
|
||||||
|
|
||||||
|
```rust
|
||||||
|
fn vypis_statistiky(zamestnanci: &[Zamestnanec]) {
|
||||||
|
let pocty = pocet_na_oddeleni(zamestnanci);
|
||||||
|
let platy = celkovy_plat_na_oddeleni(zamestnanci);
|
||||||
|
for (oddelenie, pocet) in &pocty {
|
||||||
|
let plat = platy.get(oddelenie).unwrap_or(&0);
|
||||||
|
println!("{}: {} ľudí, celkový plat: {}", oddelenie, pocet, plat);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 10d
|
||||||
|
|
||||||
|
```rust
|
||||||
|
fn oddelenie_s_najvyssim_platom(zamestnanci: &[Zamestnanec]) -> Option<String> {
|
||||||
|
let platy = celkovy_plat_na_oddeleni(zamestnanci);
|
||||||
|
platy.into_iter()
|
||||||
|
.max_by_key(|(_, plat)| *plat)
|
||||||
|
.map(|(oddelenie, _)| oddelenie)
|
||||||
|
}
|
||||||
|
```
|
||||||
276
priprava/rust_priprava5.md
Normal file
276
priprava/rust_priprava5.md
Normal file
@@ -0,0 +1,276 @@
|
|||||||
|
# BTreeMap — krok za krokom
|
||||||
|
|
||||||
|
Každá kapitola: prečítaj, pozri príklady, urob úlohy. Až potom choď ďalej.
|
||||||
|
|
||||||
|
```rust
|
||||||
|
use std::collections::BTreeMap; // toto treba vždy
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Kapitola 1: Čo to je a rozdiel oproti HashMap
|
||||||
|
|
||||||
|
BTreeMap je to isté ako HashMap — kľúč → hodnota — ale s jedným veľkým rozdielom: **kľúče sú vždy zoradené**.
|
||||||
|
|
||||||
|
| | HashMap | BTreeMap |
|
||||||
|
|-|---------|----------|
|
||||||
|
| Poradie kľúčov | náhodné | zoradené (od najmenšieho) |
|
||||||
|
| Rýchlosť | O(1) | O(log n) |
|
||||||
|
| Kedy použiť | väčšinou | keď potrebuješ zoradené kľúče |
|
||||||
|
| Import | `use std::collections::HashMap` | `use std::collections::BTreeMap` |
|
||||||
|
|
||||||
|
```rust
|
||||||
|
use std::collections::BTreeMap;
|
||||||
|
|
||||||
|
let mut mapa = BTreeMap::new();
|
||||||
|
mapa.insert("Cyril".to_string(), 22);
|
||||||
|
mapa.insert("Anna".to_string(), 25);
|
||||||
|
mapa.insert("Boris".to_string(), 30);
|
||||||
|
|
||||||
|
// Iterácia — kľúče SÚ zoradené abecedne!
|
||||||
|
for (meno, vek) in &mapa {
|
||||||
|
println!("{}: {}", meno, vek);
|
||||||
|
}
|
||||||
|
// Anna: 25
|
||||||
|
// Boris: 30
|
||||||
|
// Cyril: 22
|
||||||
|
```
|
||||||
|
|
||||||
|
S HashMap by poradie bolo náhodné. S BTreeMap je vždy zoradené.
|
||||||
|
|
||||||
|
Pre čísla zoradí od najmenšieho:
|
||||||
|
```rust
|
||||||
|
let mut mapa = BTreeMap::new();
|
||||||
|
mapa.insert(3, "tri");
|
||||||
|
mapa.insert(1, "jedna");
|
||||||
|
mapa.insert(2, "dva");
|
||||||
|
|
||||||
|
for (k, v) in &mapa {
|
||||||
|
println!("{}: {}", k, v);
|
||||||
|
}
|
||||||
|
// 1: jedna
|
||||||
|
// 2: dva
|
||||||
|
// 3: tri
|
||||||
|
```
|
||||||
|
|
||||||
|
### Úlohy 1
|
||||||
|
|
||||||
|
**1a.** Vytvor BTreeMap s 5 menami (String) a vekmi (u32). Vypíš ich. Over, že sú zoradené abecedne.
|
||||||
|
|
||||||
|
**1b.** Vytvor BTreeMap s číslami ako kľúčmi (i32 → String). Vlož ich v náhodnom poradí. Vypíš a over, že sú zoradené.
|
||||||
|
|
||||||
|
**1c.** Vytvor rovnakú mapu raz ako HashMap, raz ako BTreeMap. Vypíš obe. Vidíš rozdiel v poradí?
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Kapitola 2: Všetko čo vieš z HashMap funguje rovnako
|
||||||
|
|
||||||
|
BTreeMap má **rovnaké API** ako HashMap. Všetko čo si sa naučil, funguje:
|
||||||
|
|
||||||
|
```rust
|
||||||
|
let mut mapa = BTreeMap::new();
|
||||||
|
|
||||||
|
// insert — rovnaké
|
||||||
|
mapa.insert("Anna".to_string(), 25);
|
||||||
|
let stara = mapa.insert("Anna".to_string(), 26); // Some(25)
|
||||||
|
|
||||||
|
// get — rovnaké
|
||||||
|
let vek = mapa.get("Anna"); // Some(&26)
|
||||||
|
|
||||||
|
// contains_key — rovnaké
|
||||||
|
let je_tam = mapa.contains_key("Anna"); // true
|
||||||
|
|
||||||
|
// remove — rovnaké
|
||||||
|
let odstraneny = mapa.remove("Anna"); // Some(26)
|
||||||
|
|
||||||
|
// len, is_empty — rovnaké
|
||||||
|
let pocet = mapa.len();
|
||||||
|
let prazdna = mapa.is_empty();
|
||||||
|
|
||||||
|
// entry API — rovnaké!
|
||||||
|
*mapa.entry("Boris".to_string()).or_insert(0) += 1;
|
||||||
|
mapa.entry("Cyril".to_string()).or_default();
|
||||||
|
mapa.entry("Dana".to_string())
|
||||||
|
.and_modify(|v| *v += 1)
|
||||||
|
.or_insert(1);
|
||||||
|
|
||||||
|
// get_mut — rovnaké
|
||||||
|
if let Some(vek) = mapa.get_mut("Boris") {
|
||||||
|
*vek += 10;
|
||||||
|
}
|
||||||
|
|
||||||
|
// iterácia — rovnaká syntax, ale ZORADENÉ
|
||||||
|
for (k, v) in &mapa { /* zoradené podľa kľúča */ }
|
||||||
|
for k in mapa.keys() { /* zoradené */ }
|
||||||
|
for v in mapa.values() { /* v poradí podľa zoradených kľúčov */ }
|
||||||
|
for v in mapa.values_mut() { *v += 1; }
|
||||||
|
```
|
||||||
|
|
||||||
|
Jediný rozdiel je, že výstup je vždy zoradený.
|
||||||
|
|
||||||
|
### Úlohy 2
|
||||||
|
|
||||||
|
**2a.** Spočítaj výskyt každého znaku v `"abrakadabra"` do BTreeMap. Vypíš. V akom poradí sú znaky?
|
||||||
|
|
||||||
|
**2b.** Máš vektor slov. Zoskup ich podľa prvého písmena do `BTreeMap<char, Vec<String>>`. Over, že písmená sú zoradené.
|
||||||
|
|
||||||
|
**2c.** Napíš funkciu:
|
||||||
|
```rust
|
||||||
|
fn pocitaj_slova(text: &str) -> BTreeMap<String, usize>
|
||||||
|
```
|
||||||
|
Počet výskytov každého slova, zoradené abecedne.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Kapitola 3: Range queries — to čo HashMap nevie
|
||||||
|
|
||||||
|
Najväčšia výhoda BTreeMap: vieš sa pýtať na **rozsahy** kľúčov.
|
||||||
|
|
||||||
|
### range — podmnožina podľa rozsahu kľúčov
|
||||||
|
|
||||||
|
```rust
|
||||||
|
let mut mapa = BTreeMap::new();
|
||||||
|
mapa.insert(1, "jedna");
|
||||||
|
mapa.insert(2, "dva");
|
||||||
|
mapa.insert(3, "tri");
|
||||||
|
mapa.insert(4, "štyri");
|
||||||
|
mapa.insert(5, "päť");
|
||||||
|
mapa.insert(6, "šesť");
|
||||||
|
mapa.insert(7, "sedem");
|
||||||
|
|
||||||
|
// Kľúče od 3 do 5 (vrátane oboch)
|
||||||
|
for (k, v) in mapa.range(3..=5) {
|
||||||
|
println!("{}: {}", k, v);
|
||||||
|
}
|
||||||
|
// 3: tri
|
||||||
|
// 4: štyri
|
||||||
|
// 5: päť
|
||||||
|
|
||||||
|
// Kľúče od 3 (bez 6)
|
||||||
|
for (k, v) in mapa.range(3..6) {
|
||||||
|
println!("{}: {}", k, v);
|
||||||
|
}
|
||||||
|
// 3: tri
|
||||||
|
// 4: štyri
|
||||||
|
// 5: päť
|
||||||
|
|
||||||
|
// Kľúče od začiatku po 3 (vrátane)
|
||||||
|
for (k, v) in mapa.range(..=3) {
|
||||||
|
println!("{}: {}", k, v);
|
||||||
|
}
|
||||||
|
// 1: jedna
|
||||||
|
// 2: dva
|
||||||
|
// 3: tri
|
||||||
|
|
||||||
|
// Kľúče od 5 do konca
|
||||||
|
for (k, v) in mapa.range(5..) {
|
||||||
|
println!("{}: {}", k, v);
|
||||||
|
}
|
||||||
|
// 5: päť
|
||||||
|
// 6: šesť
|
||||||
|
// 7: sedem
|
||||||
|
```
|
||||||
|
|
||||||
|
S Stringami to funguje abecedne:
|
||||||
|
```rust
|
||||||
|
let mut mapa = BTreeMap::new();
|
||||||
|
mapa.insert("Anna".to_string(), 25);
|
||||||
|
mapa.insert("Boris".to_string(), 30);
|
||||||
|
mapa.insert("Cyril".to_string(), 22);
|
||||||
|
mapa.insert("Dana".to_string(), 28);
|
||||||
|
|
||||||
|
// Mená od "B" po "D" (nezahrnie "D" lebo ..)
|
||||||
|
for (meno, vek) in mapa.range("B".to_string().."D".to_string()) {
|
||||||
|
println!("{}: {}", meno, vek);
|
||||||
|
}
|
||||||
|
// Boris: 30
|
||||||
|
// Cyril: 22
|
||||||
|
```
|
||||||
|
|
||||||
|
### Úlohy 3
|
||||||
|
|
||||||
|
**3a.** Vytvor BTreeMap s kľúčmi 1 až 10 (i32 → String s názvom čísla). Vypíš len čísla 4 až 7.
|
||||||
|
|
||||||
|
**3b.** Máš BTreeMap študentov (meno → priemer). Vypíš len študentov, ktorých meno začína na písmená M až Z. Použi `.range()`.
|
||||||
|
|
||||||
|
**3c.** Máš BTreeMap teplôt za dni v mesiaci (u32 → f64, deň → teplota). Napíš funkciu:
|
||||||
|
```rust
|
||||||
|
fn teploty_v_tyzdni(teploty: &BTreeMap<u32, f64>, od: u32, do_: u32) -> Vec<f64>
|
||||||
|
```
|
||||||
|
Vráti vektor teplôt pre dané dni.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Kapitola 4: first/last — prvý a posledný kľúč
|
||||||
|
|
||||||
|
BTreeMap vie efektívne nájsť najmenší a najväčší kľúč:
|
||||||
|
|
||||||
|
```rust
|
||||||
|
let mut mapa = BTreeMap::new();
|
||||||
|
mapa.insert(5, "päť");
|
||||||
|
mapa.insert(1, "jedna");
|
||||||
|
mapa.insert(9, "deväť");
|
||||||
|
mapa.insert(3, "tri");
|
||||||
|
|
||||||
|
// Prvý (najmenší) pár
|
||||||
|
let prvy = mapa.first_key_value();
|
||||||
|
// Some((&1, &"jedna"))
|
||||||
|
|
||||||
|
// Posledný (najväčší) pár
|
||||||
|
let posledny = mapa.last_key_value();
|
||||||
|
// Some((&9, &"deväť"))
|
||||||
|
|
||||||
|
// Len kľúče
|
||||||
|
let prvy_kluc = mapa.keys().next(); // Some(&1)
|
||||||
|
let posledny_kluc = mapa.keys().last(); // Some(&9)
|
||||||
|
```
|
||||||
|
|
||||||
|
Tieto operácie sú O(log n) — veľmi rýchle. HashMap toto nevie (musel by prejsť celú mapu).
|
||||||
|
|
||||||
|
### Úlohy 4
|
||||||
|
|
||||||
|
**4a.** Máš BTreeMap študentov (meno → priemer). Nájdi študenta s menom prvým v abecede a posledným v abecede.
|
||||||
|
|
||||||
|
**4b.** Máš BTreeMap (rok: u32 → udalosť: String). Nájdi najstaršiu a najnovšiu udalosť.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Kapitola 5: Kedy HashMap, kedy BTreeMap
|
||||||
|
|
||||||
|
| Situácia | Použi |
|
||||||
|
|----------|-------|
|
||||||
|
| Nepotrebuješ poradie | HashMap (rýchlejší) |
|
||||||
|
| Chceš zoradený výpis | BTreeMap |
|
||||||
|
| Potrebuješ range queries | BTreeMap |
|
||||||
|
| Potrebuješ prvý/posledný | BTreeMap |
|
||||||
|
| Chceš maximálny výkon | HashMap |
|
||||||
|
| Na skúške: `vypis_statistiky` zoradene | BTreeMap |
|
||||||
|
|
||||||
|
**Tip na skúšku:** Ak zadanie hovorí "vypíš v abecednom poradí" alebo "zoradene", použi BTreeMap. Inak HashMap stačí.
|
||||||
|
|
||||||
|
Konverzia medzi nimi je jednoduchá:
|
||||||
|
```rust
|
||||||
|
use std::collections::{HashMap, BTreeMap};
|
||||||
|
|
||||||
|
// HashMap → BTreeMap
|
||||||
|
let hash: HashMap<String, i32> = /* ... */;
|
||||||
|
let btree: BTreeMap<String, i32> = hash.into_iter().collect();
|
||||||
|
|
||||||
|
// BTreeMap → HashMap
|
||||||
|
let btree: BTreeMap<String, i32> = /* ... */;
|
||||||
|
let hash: HashMap<String, i32> = btree.into_iter().collect();
|
||||||
|
```
|
||||||
|
|
||||||
|
### Úlohy 5
|
||||||
|
|
||||||
|
**5a.** Máš:
|
||||||
|
```rust
|
||||||
|
struct Zamestnanec { meno: String, oddelenie: String, plat: u32 }
|
||||||
|
```
|
||||||
|
Napíš funkciu `pocet_na_oddeleni(zamestnanci: &[Zamestnanec]) -> BTreeMap<String, usize>` — počet ľudí na oddelení, výstup zoradený podľa názvu oddelenia.
|
||||||
|
|
||||||
|
**5b.** Máš vektor slov. Spočítaj výskyt každého slova a výstup zoradeného (BTreeMap). Potom vypíš len slová, ktoré sa vyskytli viac ako 2x.
|
||||||
|
|
||||||
|
**5c.** Máš BTreeMap známok študenta (predmet → známka). Napíš funkcie:
|
||||||
|
- `najlepsia_znamka(znamky: &BTreeMap<String, u8>) -> Option<(&String, &u8)>` — predmet s najlepšou (najnižšou) známkou
|
||||||
|
- `predmety_v_rozsahu(znamky: &BTreeMap<String, u8>, od: &str, do_: &str) -> Vec<(&String, &u8)>` — predmety s názvom v danom abecednom rozsahu
|
||||||
474
priprava/rust_priprava6.md
Normal file
474
priprava/rust_priprava6.md
Normal file
@@ -0,0 +1,474 @@
|
|||||||
|
# HashSet — krok za krokom
|
||||||
|
|
||||||
|
Každá kapitola: prečítaj, pozri príklady, urob úlohy. Až potom choď ďalej.
|
||||||
|
|
||||||
|
```rust
|
||||||
|
use std::collections::HashSet; // toto treba vždy
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Kapitola 1: Čo to je a vytváranie
|
||||||
|
|
||||||
|
HashSet je kolekcia **unikátnych hodnôt**. Žiadna hodnota sa neopakuje. Negarantuje poradie.
|
||||||
|
|
||||||
|
Rozdiel oproti Vec: Vec môže mať duplikáty a pamätá poradie.
|
||||||
|
Rozdiel oproti HashMap: HashMap má kľúč → hodnota. HashSet má len hodnotu (žiadny pár).
|
||||||
|
|
||||||
|
```rust
|
||||||
|
// Prázdny set
|
||||||
|
let mut mnozina: HashSet<i32> = HashSet::new();
|
||||||
|
|
||||||
|
// Alebo nechaj Rust odvodiť:
|
||||||
|
let mut mnozina = HashSet::new();
|
||||||
|
mnozina.insert(1); // teraz Rust vie: HashSet<i32>
|
||||||
|
|
||||||
|
// Z vektora — duplikáty zmiznú!
|
||||||
|
let cisla = vec![1, 2, 3, 2, 1, 4, 3, 5];
|
||||||
|
let unikatne: HashSet<i32> = cisla.into_iter().collect();
|
||||||
|
// {1, 2, 3, 4, 5} — len 5 prvkov, nie 8
|
||||||
|
|
||||||
|
// Z reťazca — množina znakov
|
||||||
|
let znaky: HashSet<char> = "abrakadabra".chars().collect();
|
||||||
|
// {'a', 'b', 'r', 'k', 'd'} — len 5 unikátnych
|
||||||
|
```
|
||||||
|
|
||||||
|
### Úlohy 1
|
||||||
|
|
||||||
|
**1a.** Vytvor HashSet čísel z vektora `[5, 3, 5, 1, 3, 2, 1, 4]`. Vypíš koľko prvkov má. Vypíš prvky.
|
||||||
|
|
||||||
|
**1b.** Vytvor HashSet znakov z reťazca `"hello world"`. Koľko unikátnych znakov to má? (vrátane medzery)
|
||||||
|
|
||||||
|
**1c.** Čo vypíše? Tipni, potom over:
|
||||||
|
```rust
|
||||||
|
let v = vec![10, 20, 10, 30, 20, 10];
|
||||||
|
let s: HashSet<i32> = v.into_iter().collect();
|
||||||
|
println!("{}", s.len());
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Kapitola 2: insert — vráti bool!
|
||||||
|
|
||||||
|
Toto je kľúčový rozdiel oproti HashMap. `insert` vráti `bool`:
|
||||||
|
- `true` → prvok bol **nový**, vložil sa
|
||||||
|
- `false` → prvok už **existoval**, nič sa nezmenilo
|
||||||
|
|
||||||
|
```rust
|
||||||
|
let mut mnozina = HashSet::new();
|
||||||
|
|
||||||
|
let novy = mnozina.insert("Anna".to_string());
|
||||||
|
// novy = true — Anna bola pridaná
|
||||||
|
|
||||||
|
let novy = mnozina.insert("Anna".to_string());
|
||||||
|
// novy = false — Anna už existuje, nič sa nezmenilo
|
||||||
|
```
|
||||||
|
|
||||||
|
**Praktické — detekcia duplikátov:**
|
||||||
|
```rust
|
||||||
|
let mut videne = HashSet::new();
|
||||||
|
let slova = vec!["ahoj", "svet", "ahoj", "rust"];
|
||||||
|
|
||||||
|
for slovo in &slova {
|
||||||
|
if !videne.insert(*slovo) {
|
||||||
|
println!("Duplikát: {}", slovo);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Vypíše: Duplikát: ahoj
|
||||||
|
```
|
||||||
|
|
||||||
|
Logika: `insert` vráti `false` → prvok tam už bol → je to duplikát.
|
||||||
|
|
||||||
|
### Úlohy 2
|
||||||
|
|
||||||
|
**2a.** Napíš funkciu `ma_duplikaty(cisla: &[i32]) -> bool`. Použi HashSet a insert. Vráť true hneď ako nájdeš prvý duplikát.
|
||||||
|
|
||||||
|
**2b.** Napíš funkciu `najdi_duplikaty(cisla: &[i32]) -> Vec<i32>` — vráti vektor všetkých duplikovaných hodnôt (každý duplikát len raz). Hint: použi dva HashSety — `videne` a `duplikaty`.
|
||||||
|
|
||||||
|
**2c.** Čo vypíše? Tipni:
|
||||||
|
```rust
|
||||||
|
let mut s = HashSet::new();
|
||||||
|
println!("{}", s.insert(1));
|
||||||
|
println!("{}", s.insert(2));
|
||||||
|
println!("{}", s.insert(1));
|
||||||
|
println!("{}", s.insert(3));
|
||||||
|
println!("{}", s.insert(2));
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Kapitola 3: contains, remove, len
|
||||||
|
|
||||||
|
```rust
|
||||||
|
let mut mnozina = HashSet::new();
|
||||||
|
mnozina.insert("Anna".to_string());
|
||||||
|
mnozina.insert("Boris".to_string());
|
||||||
|
|
||||||
|
// contains — je tam?
|
||||||
|
mnozina.contains("Anna"); // true
|
||||||
|
mnozina.contains("Cyril"); // false
|
||||||
|
|
||||||
|
// len — počet prvkov
|
||||||
|
mnozina.len(); // 2
|
||||||
|
|
||||||
|
// is_empty
|
||||||
|
mnozina.is_empty(); // false
|
||||||
|
|
||||||
|
// remove — vráti bool (true ak existoval a bol odstránený)
|
||||||
|
mnozina.remove("Anna"); // true — Anna odstránená
|
||||||
|
mnozina.remove("Cyril"); // false — Cyril tam ani nebol
|
||||||
|
|
||||||
|
// clear — vymaž všetko
|
||||||
|
mnozina.clear();
|
||||||
|
```
|
||||||
|
|
||||||
|
**Dôležité:** `contains` na HashSet je O(1) — veľmi rýchle. Na Vec je O(n) — pomalé. Ak často kontroluješ existenciu, použi HashSet.
|
||||||
|
|
||||||
|
```rust
|
||||||
|
// POMALÉ — Vec.contains prechádza celý vektor
|
||||||
|
let povolene = vec!["admin", "editor", "viewer"];
|
||||||
|
povolene.contains(&"admin"); // O(n)
|
||||||
|
|
||||||
|
// RÝCHLE — HashSet.contains
|
||||||
|
let povolene: HashSet<&str> = vec!["admin", "editor", "viewer"].into_iter().collect();
|
||||||
|
povolene.contains("admin"); // O(1)
|
||||||
|
```
|
||||||
|
|
||||||
|
### Úlohy 3
|
||||||
|
|
||||||
|
**3a.** Vytvor HashSet povolených farieb: "červená", "modrá", "zelená". Napíš funkciu:
|
||||||
|
```rust
|
||||||
|
fn je_povolena(povolene: &HashSet<String>, farba: &str) -> bool
|
||||||
|
```
|
||||||
|
|
||||||
|
**3b.** Napíš funkciu `pocet_unikatnych(cisla: &[i32]) -> usize` — koľko rôznych hodnôt je vo vektore.
|
||||||
|
|
||||||
|
**3c.** Máš HashSet mien. Odstráň všetky mená kratšie ako 4 znaky. Použi `.retain()`:
|
||||||
|
```rust
|
||||||
|
// retain nechá len prvky, kde closure vráti true
|
||||||
|
mnozina.retain(|meno| meno.len() >= 4);
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Kapitola 4: Iterácia
|
||||||
|
|
||||||
|
```rust
|
||||||
|
let mnozina: HashSet<i32> = vec![3, 1, 4, 1, 5].into_iter().collect();
|
||||||
|
|
||||||
|
// Základná iterácia — poradie NIE JE garantované!
|
||||||
|
for prvok in &mnozina {
|
||||||
|
println!("{}", prvok);
|
||||||
|
}
|
||||||
|
|
||||||
|
// filter + collect — vyfiltruj do nového HashSetu
|
||||||
|
let parne: HashSet<&i32> = mnozina.iter().filter(|c| *c % 2 == 0).collect();
|
||||||
|
|
||||||
|
// Do Vec
|
||||||
|
let vektor: Vec<&i32> = mnozina.iter().collect();
|
||||||
|
|
||||||
|
// any — existuje prvok splňajúci podmienku?
|
||||||
|
let ma_velke: bool = mnozina.iter().any(|c| *c > 3);
|
||||||
|
|
||||||
|
// count s filtrom
|
||||||
|
let pocet_parnych: usize = mnozina.iter().filter(|c| *c % 2 == 0).count();
|
||||||
|
|
||||||
|
// sum
|
||||||
|
let sucet: i32 = mnozina.iter().sum();
|
||||||
|
```
|
||||||
|
|
||||||
|
### Úlohy 4
|
||||||
|
|
||||||
|
**4a.** Máš HashSet mien (String). Vypíš len mená začínajúce na 'A'.
|
||||||
|
|
||||||
|
**4b.** Napíš funkciu `sucet(mnozina: &HashSet<i32>) -> i32` — súčet všetkých prvkov.
|
||||||
|
|
||||||
|
**4c.** Napíš funkciu `najdlhsi(mnozina: &HashSet<String>) -> Option<&String>` — najdlhší reťazec. Použi `.max_by_key()`.
|
||||||
|
|
||||||
|
**4d.** Máš HashSet čísel. Koľko z nich je deliteľných 3? Napíš to jedným výrazom.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Kapitola 5: Prienik (intersection)
|
||||||
|
|
||||||
|
Prienik = prvky, ktoré sú v **oboch** množinách.
|
||||||
|
|
||||||
|
```rust
|
||||||
|
let a: HashSet<i32> = vec![1, 2, 3, 4].into_iter().collect();
|
||||||
|
let b: HashSet<i32> = vec![3, 4, 5, 6].into_iter().collect();
|
||||||
|
|
||||||
|
// intersection vráti iterátor cez &i32
|
||||||
|
let prienik: HashSet<&i32> = a.intersection(&b).collect();
|
||||||
|
// {&3, &4}
|
||||||
|
|
||||||
|
// Ak chceš vlastné hodnoty (nie referencie), použi .copied()
|
||||||
|
let prienik: HashSet<i32> = a.intersection(&b).copied().collect();
|
||||||
|
// {3, 4}
|
||||||
|
|
||||||
|
// Alebo do Vec
|
||||||
|
let prienik: Vec<&i32> = a.intersection(&b).collect();
|
||||||
|
// [&3, &4]
|
||||||
|
```
|
||||||
|
|
||||||
|
**Skratka operátorom:**
|
||||||
|
```rust
|
||||||
|
let prienik: HashSet<i32> = &a & &b;
|
||||||
|
// {3, 4} — rovnaký výsledok, kratší zápis
|
||||||
|
```
|
||||||
|
|
||||||
|
### Úlohy 5
|
||||||
|
|
||||||
|
**5a.** Máš dva zoznamy mien (Vec<String>). Preveď ich na HashSety a nájdi spoločné mená.
|
||||||
|
```rust
|
||||||
|
let trieda_a = vec!["Anna", "Boris", "Cyril", "Dana"];
|
||||||
|
let trieda_b = vec!["Boris", "Dana", "Emil", "Fero"];
|
||||||
|
// Spoločné: Boris, Dana
|
||||||
|
```
|
||||||
|
|
||||||
|
**5b.** Napíš funkciu:
|
||||||
|
```rust
|
||||||
|
fn spolocne_pismena(slovo1: &str, slovo2: &str) -> HashSet<char>
|
||||||
|
```
|
||||||
|
Vráti písmená, ktoré sú v oboch slovách.
|
||||||
|
|
||||||
|
**5c.** Máš 3 HashSety. Nájdi prvky, ktoré sú vo všetkých troch. Hint: najprv prienik A∩B, potom výsledok ∩ C.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Kapitola 6: Zjednotenie (union)
|
||||||
|
|
||||||
|
Zjednotenie = prvky, ktoré sú v **aspoň jednej** z množín. Duplikáty sa nezopakujú.
|
||||||
|
|
||||||
|
```rust
|
||||||
|
let a: HashSet<i32> = vec![1, 2, 3].into_iter().collect();
|
||||||
|
let b: HashSet<i32> = vec![3, 4, 5].into_iter().collect();
|
||||||
|
|
||||||
|
let zjednotenie: HashSet<&i32> = a.union(&b).collect();
|
||||||
|
// {&1, &2, &3, &4, &5}
|
||||||
|
|
||||||
|
let zjednotenie: HashSet<i32> = a.union(&b).copied().collect();
|
||||||
|
// {1, 2, 3, 4, 5}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Skratka:**
|
||||||
|
```rust
|
||||||
|
let zjednotenie: HashSet<i32> = &a | &b;
|
||||||
|
```
|
||||||
|
|
||||||
|
### Úlohy 6
|
||||||
|
|
||||||
|
**6a.** Máš záujmy dvoch ľudí ako HashSety. Nájdi všetky záujmy dokopy (bez duplikátov).
|
||||||
|
|
||||||
|
**6b.** Napíš funkciu:
|
||||||
|
```rust
|
||||||
|
fn vsetky_unikatne_znaky(texty: &[String]) -> HashSet<char>
|
||||||
|
```
|
||||||
|
Vráti množinu všetkých znakov zo všetkých textov. Hint: iteruj cez texty a postupne rob union, alebo jednoducho insertuj do jedného HashSetu.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Kapitola 7: Rozdiel (difference)
|
||||||
|
|
||||||
|
Rozdiel = prvky v **prvej**, ktoré nie sú v **druhej**.
|
||||||
|
|
||||||
|
```rust
|
||||||
|
let a: HashSet<i32> = vec![1, 2, 3, 4].into_iter().collect();
|
||||||
|
let b: HashSet<i32> = vec![3, 4, 5, 6].into_iter().collect();
|
||||||
|
|
||||||
|
// Prvky v A, ktoré NIE SÚ v B
|
||||||
|
let rozdiel: HashSet<i32> = a.difference(&b).copied().collect();
|
||||||
|
// {1, 2}
|
||||||
|
|
||||||
|
// Opačný smer — prvky v B, ktoré NIE SÚ v A
|
||||||
|
let rozdiel_opacny: HashSet<i32> = b.difference(&a).copied().collect();
|
||||||
|
// {5, 6}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Skratka:**
|
||||||
|
```rust
|
||||||
|
let rozdiel: HashSet<i32> = &a - &b; // {1, 2}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Symetrický rozdiel** = prvky v jednej ALEBO druhej, ale nie v oboch:
|
||||||
|
```rust
|
||||||
|
let sym: HashSet<i32> = a.symmetric_difference(&b).copied().collect();
|
||||||
|
// {1, 2, 5, 6}
|
||||||
|
|
||||||
|
// Skratka:
|
||||||
|
let sym: HashSet<i32> = &a ^ &b;
|
||||||
|
```
|
||||||
|
|
||||||
|
### Úlohy 7
|
||||||
|
|
||||||
|
**7a.** Máš zoznam všetkých študentov a zoznam prítomných. Nájdi kto chýba:
|
||||||
|
```rust
|
||||||
|
let vsetci: HashSet<String> = /* Anna, Boris, Cyril, Dana, Emil */;
|
||||||
|
let pritomni: HashSet<String> = /* Anna, Cyril, Emil */;
|
||||||
|
// Chýba: Boris, Dana
|
||||||
|
```
|
||||||
|
|
||||||
|
**7b.** Napíš funkciu:
|
||||||
|
```rust
|
||||||
|
fn chybajuce_pismena(slovo: &str) -> HashSet<char>
|
||||||
|
```
|
||||||
|
Vráti písmená abecedy (a-z), ktoré sa v slove nenachádzajú. Hint: `('a'..='z').collect()` ti dá HashSet celej abecedy.
|
||||||
|
|
||||||
|
**7c.** Máš dva Vec<i32>. Nájdi čísla, ktoré sú len v jednom z nich (nie v oboch). Použi symetrický rozdiel.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Kapitola 8: Podmnožina, nadmnožina, disjunkcia
|
||||||
|
|
||||||
|
```rust
|
||||||
|
let mala: HashSet<i32> = vec![1, 2].into_iter().collect();
|
||||||
|
let velka: HashSet<i32> = vec![1, 2, 3, 4].into_iter().collect();
|
||||||
|
let ina: HashSet<i32> = vec![5, 6].into_iter().collect();
|
||||||
|
|
||||||
|
// is_subset — je mala podmnožinou velka?
|
||||||
|
mala.is_subset(&velka); // true — všetky prvky mala sú vo velka
|
||||||
|
|
||||||
|
// is_superset — je velka nadmnožinou mala?
|
||||||
|
velka.is_superset(&mala); // true — velka obsahuje všetko z mala
|
||||||
|
|
||||||
|
// is_disjoint — nemajú nič spoločné?
|
||||||
|
mala.is_disjoint(&ina); // true — žiadny spoločný prvok
|
||||||
|
mala.is_disjoint(&velka); // false — majú spoločné 1 a 2
|
||||||
|
```
|
||||||
|
|
||||||
|
### Úlohy 8
|
||||||
|
|
||||||
|
**8a.** Máš povinné predmety a predmety, ktoré študent absolvoval. Napíš funkciu:
|
||||||
|
```rust
|
||||||
|
fn splnil_vsetky(povinne: &HashSet<String>, absolvovane: &HashSet<String>) -> bool
|
||||||
|
```
|
||||||
|
Vráti true ak absolvoval všetky povinné. Jeden riadok.
|
||||||
|
|
||||||
|
**8b.** Máš dve skupiny ľudí. Napíš funkciu, ktorá zistí, či sa skupiny vôbec neprekrývajú:
|
||||||
|
```rust
|
||||||
|
fn su_nezavisle(a: &HashSet<String>, b: &HashSet<String>) -> bool
|
||||||
|
```
|
||||||
|
|
||||||
|
**8c.** Študent má predmety. Máš set povinných, set voliteľných. Napíš:
|
||||||
|
- `splnil_povinne(studentove: &HashSet<String>, povinne: &HashSet<String>) -> bool`
|
||||||
|
- `ktore_povinne_chybaju(studentove: &HashSet<String>, povinne: &HashSet<String>) -> HashSet<String>` — ktoré povinné mu ešte chýbajú
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Kapitola 9: Prehľad operátorov
|
||||||
|
|
||||||
|
Všetky množinové operácie majú aj skrátený zápis:
|
||||||
|
|
||||||
|
```rust
|
||||||
|
let a: HashSet<i32> = vec![1, 2, 3].into_iter().collect();
|
||||||
|
let b: HashSet<i32> = vec![2, 3, 4].into_iter().collect();
|
||||||
|
|
||||||
|
let prienik = &a & &b; // {2, 3}
|
||||||
|
let zjednotenie = &a | &b; // {1, 2, 3, 4}
|
||||||
|
let rozdiel = &a - &b; // {1}
|
||||||
|
let sym_rozdiel = &a ^ &b; // {1, 4}
|
||||||
|
```
|
||||||
|
|
||||||
|
Všetky vracajú nový `HashSet<i32>` (nie referencie). Pozor na `&a` — treba referencie.
|
||||||
|
|
||||||
|
### Úlohy 9
|
||||||
|
|
||||||
|
**9a.** Máš tri sety A, B, C. Napíš jedným výrazom s operátormi:
|
||||||
|
- prvky, ktoré sú vo všetkých troch
|
||||||
|
- prvky, ktoré sú v aspoň jednom
|
||||||
|
- prvky, ktoré sú v A ale nie v B ani v C
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Kapitola 10: Praktické vzory zo skúšky
|
||||||
|
|
||||||
|
### Vzor 1: Obesenec — sledovanie uhádnutých písmen
|
||||||
|
|
||||||
|
```rust
|
||||||
|
struct Obesenec {
|
||||||
|
slovo: String,
|
||||||
|
uhadnute: HashSet<char>,
|
||||||
|
skusane: HashSet<char>,
|
||||||
|
zivoty: u8,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Obesenec {
|
||||||
|
fn new(slovo: &str) -> Obesenec {
|
||||||
|
Obesenec {
|
||||||
|
slovo: slovo.to_lowercase(),
|
||||||
|
uhadnute: HashSet::new(),
|
||||||
|
skusane: HashSet::new(),
|
||||||
|
zivoty: 6,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn tipni(&mut self, pismeno: char) -> &str {
|
||||||
|
let p = pismeno.to_lowercase().next().unwrap();
|
||||||
|
|
||||||
|
// insert vráti false ak písmeno už bolo skúšané
|
||||||
|
if !self.skusane.insert(p) {
|
||||||
|
return "Už si skúšal";
|
||||||
|
}
|
||||||
|
|
||||||
|
if self.slovo.contains(p) {
|
||||||
|
self.uhadnute.insert(p);
|
||||||
|
"Správne"
|
||||||
|
} else {
|
||||||
|
self.zivoty -= 1;
|
||||||
|
"Zle"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Zobraz slovo: uhádnuté písmená, neuhádnuté ako '_'
|
||||||
|
fn zobraz(&self) -> String {
|
||||||
|
self.slovo.chars().map(|c| {
|
||||||
|
if self.uhadnute.contains(&c) { c } else { '_' }
|
||||||
|
}).collect()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Vyhral ak všetky písmená slova sú v uhadnute
|
||||||
|
fn vyhral(&self) -> bool {
|
||||||
|
self.slovo.chars().all(|c| self.uhadnute.contains(&c))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Kľúčové veci:
|
||||||
|
- `skusane.insert(p)` vráti `false` → písmeno už bolo → preskočíme
|
||||||
|
- `uhadnute.contains(&c)` → rýchla kontrola pre každý znak slova
|
||||||
|
- `slovo.chars().all(|c| uhadnute.contains(&c))` → vyhral ak uhádol všetky
|
||||||
|
|
||||||
|
### Vzor 2: Unikátne hodnoty z kolekcie štruktúr
|
||||||
|
|
||||||
|
```rust
|
||||||
|
struct Kniha { nazov: String, zaner: String }
|
||||||
|
|
||||||
|
fn unikatne_zanre(knihy: &[Kniha]) -> HashSet<String> {
|
||||||
|
knihy.iter().map(|k| k.zaner.clone()).collect()
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Vzor 3: Rýchle vyhľadávanie v cykle
|
||||||
|
|
||||||
|
```rust
|
||||||
|
// Ak kontroluješ contains opakovane, preveď Vec na HashSet
|
||||||
|
fn najdi_spolocne(kniznica: &[Kniha], pozicane_nazvy: &[String]) -> Vec<&Kniha> {
|
||||||
|
let nazvy_set: HashSet<&String> = pozicane_nazvy.iter().collect();
|
||||||
|
kniznica.iter()
|
||||||
|
.filter(|k| nazvy_set.contains(&k.nazov))
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Úlohy 10
|
||||||
|
|
||||||
|
**10a.** Implementuj Obesenca sám od nuly. Musíš mať:
|
||||||
|
- `new(slovo: &str) -> Obesenec`
|
||||||
|
- `tipni(&mut self, pismeno: char) -> bool` — true ak správne
|
||||||
|
- `zobraz(&self) -> String` — slovo s '_' za neuhádnuté
|
||||||
|
- `je_koniec(&self) -> bool` — true ak vyhral alebo zivoty == 0
|
||||||
|
|
||||||
|
**10b.** Máš vektor študentov s `predmety: Vec<String>`. Napíš:
|
||||||
|
- `vsetky_predmety(studenti: &[Student]) -> HashSet<String>`
|
||||||
|
- `studenti_s_predmetom(studenti: &[Student], predmet: &str) -> Vec<&Student>`
|
||||||
|
|
||||||
|
**10c.** Máš `povinne_predmety: HashSet<String>` a `absolvovane: HashSet<String>`. Vypíš: koľko povinných splnil, koľko mu chýba, ktoré mu chýbajú.
|
||||||
540
priprava/rust_priprava7.md
Normal file
540
priprava/rust_priprava7.md
Normal file
@@ -0,0 +1,540 @@
|
|||||||
|
# itertools — krok za krokom
|
||||||
|
|
||||||
|
Každá kapitola: prečítaj, pozri príklady, urob úlohy. Až potom choď ďalej.
|
||||||
|
|
||||||
|
```rust
|
||||||
|
use itertools::Itertools; // toto treba vždy
|
||||||
|
```
|
||||||
|
|
||||||
|
`Cargo.toml`:
|
||||||
|
```toml
|
||||||
|
[dependencies]
|
||||||
|
itertools = "0.14"
|
||||||
|
```
|
||||||
|
|
||||||
|
itertools pridáva metódy na každý iterátor. Nič špeciálne netreba robiť — len `use itertools::Itertools` a všetky metódy sú k dispozícii na `.iter()`, `.into_iter()` atď.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Kapitola 1: sorted — zoradenie iterátora
|
||||||
|
|
||||||
|
Štandardný Rust nemá `.sorted()` na iterátoroch. itertools ho pridáva.
|
||||||
|
|
||||||
|
```rust
|
||||||
|
use itertools::Itertools;
|
||||||
|
|
||||||
|
let cisla = vec![3, 1, 4, 1, 5, 9, 2, 6];
|
||||||
|
|
||||||
|
// sorted() — zoradí vzostupne, vráti nový iterátor
|
||||||
|
let zoradene: Vec<i32> = cisla.iter().copied().sorted().collect();
|
||||||
|
// [1, 1, 2, 3, 4, 5, 6, 9]
|
||||||
|
|
||||||
|
// sorted_by — vlastné porovnanie
|
||||||
|
let zostupne: Vec<i32> = cisla.iter().copied()
|
||||||
|
.sorted_by(|a, b| b.cmp(a))
|
||||||
|
.collect();
|
||||||
|
// [9, 6, 5, 4, 3, 2, 1, 1]
|
||||||
|
|
||||||
|
// sorted_by_key — zoraď podľa kľúča
|
||||||
|
let slova = vec!["banán", "auto", "citrón"];
|
||||||
|
let podla_dlzky: Vec<&str> = slova.into_iter()
|
||||||
|
.sorted_by_key(|s| s.len())
|
||||||
|
.collect();
|
||||||
|
// ["auto", "banán", "citrón"]
|
||||||
|
```
|
||||||
|
|
||||||
|
So štruktúrami:
|
||||||
|
```rust
|
||||||
|
struct Student { meno: String, priemer: f32 }
|
||||||
|
|
||||||
|
let studenti = vec![
|
||||||
|
Student { meno: "Cyril".into(), priemer: 1.5 },
|
||||||
|
Student { meno: "Anna".into(), priemer: 2.1 },
|
||||||
|
Student { meno: "Boris".into(), priemer: 1.2 },
|
||||||
|
];
|
||||||
|
|
||||||
|
// Zoraď podľa priemeru
|
||||||
|
let zoradeni: Vec<&Student> = studenti.iter()
|
||||||
|
.sorted_by(|a, b| a.priemer.partial_cmp(&b.priemer).unwrap())
|
||||||
|
.collect();
|
||||||
|
// Boris (1.2), Cyril (1.5), Anna (2.1)
|
||||||
|
|
||||||
|
// Zoraď podľa mena abecedne
|
||||||
|
let abecedne: Vec<&Student> = studenti.iter()
|
||||||
|
.sorted_by_key(|s| &s.meno)
|
||||||
|
.collect();
|
||||||
|
// Anna, Boris, Cyril
|
||||||
|
```
|
||||||
|
|
||||||
|
**Bez itertools** by si musel klonovať do Vec a volať `.sort()`:
|
||||||
|
```rust
|
||||||
|
// Bez itertools — zbytočne komplikované
|
||||||
|
let mut kopie = studenti.clone();
|
||||||
|
kopie.sort_by(|a, b| a.priemer.partial_cmp(&b.priemer).unwrap());
|
||||||
|
|
||||||
|
// S itertools — jednoduché reťazenie
|
||||||
|
let vysledok: Vec<&Student> = studenti.iter()
|
||||||
|
.sorted_by(|a, b| a.priemer.partial_cmp(&b.priemer).unwrap())
|
||||||
|
.collect();
|
||||||
|
```
|
||||||
|
|
||||||
|
### Úlohy 1
|
||||||
|
|
||||||
|
**1a.** Máš vektor mien. Zoraď ich abecedne pomocou `.sorted()`. Vypíš.
|
||||||
|
|
||||||
|
**1b.** Máš vektor čísel. Zoraď zostupne pomocou `.sorted_by()`.
|
||||||
|
|
||||||
|
**1c.** Máš vektor reťazcov. Zoraď podľa dĺžky (najkratšie prvé) pomocou `.sorted_by_key()`.
|
||||||
|
|
||||||
|
**1d.** Máš `Vec<(String, u32)>` — mená a veky. Zoraď podľa veku zostupne.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Kapitola 2: unique — odstránenie duplikátov
|
||||||
|
|
||||||
|
```rust
|
||||||
|
use itertools::Itertools;
|
||||||
|
|
||||||
|
let cisla = vec![1, 3, 2, 1, 4, 3, 2, 1, 5];
|
||||||
|
|
||||||
|
// unique() — odstráni duplikáty, zachová prvý výskyt
|
||||||
|
let unikatne: Vec<&i32> = cisla.iter().unique().collect();
|
||||||
|
// [&1, &3, &2, &4, &5] — poradie prvého výskytu je zachované!
|
||||||
|
|
||||||
|
// S owned hodnotami
|
||||||
|
let unikatne: Vec<i32> = cisla.into_iter().unique().collect();
|
||||||
|
// [1, 3, 2, 4, 5]
|
||||||
|
```
|
||||||
|
|
||||||
|
Rozdiel oproti HashSet: `unique()` **zachováva poradie** prvého výskytu. HashSet nie.
|
||||||
|
|
||||||
|
```rust
|
||||||
|
// unique_by — odstráni duplikáty podľa kľúča
|
||||||
|
struct Student { meno: String, trieda: String }
|
||||||
|
|
||||||
|
let studenti = vec![
|
||||||
|
Student { meno: "Anna".into(), trieda: "A".into() },
|
||||||
|
Student { meno: "Boris".into(), trieda: "B".into() },
|
||||||
|
Student { meno: "Cyril".into(), trieda: "A".into() },
|
||||||
|
Student { meno: "Dana".into(), trieda: "B".into() },
|
||||||
|
];
|
||||||
|
|
||||||
|
// Jeden študent z každej triedy (prvý nájdený)
|
||||||
|
let po_jednom: Vec<&Student> = studenti.iter()
|
||||||
|
.unique_by(|s| &s.trieda)
|
||||||
|
.collect();
|
||||||
|
// Anna (trieda A), Boris (trieda B) — Cyril a Dana sú duplikáty tried
|
||||||
|
```
|
||||||
|
|
||||||
|
### Úlohy 2
|
||||||
|
|
||||||
|
**2a.** Máš vektor slov s duplikátmi. Odstráň duplikáty a zachovaj poradie.
|
||||||
|
|
||||||
|
**2b.** Máš vektor `(String, i32)` — (meno, vek). Niektoré mená sa opakujú. Nechaj len prvý výskyt každého mena. Použi `unique_by`.
|
||||||
|
|
||||||
|
**2c.** Máš vektor reťazcov. Chceš unikátne slová case-insensitive (t.j. "Ahoj" a "ahoj" sú duplikáty). Použi `unique_by` s `.to_lowercase()`.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Kapitola 3: join — spojenie do reťazca
|
||||||
|
|
||||||
|
```rust
|
||||||
|
use itertools::Itertools;
|
||||||
|
|
||||||
|
let slova = vec!["ahoj", "svet", "rust"];
|
||||||
|
|
||||||
|
// join — spojí prvky oddeľovačom
|
||||||
|
let veta: String = slova.iter().join(", ");
|
||||||
|
// "ahoj, svet, rust"
|
||||||
|
|
||||||
|
let cisla = vec![1, 2, 3, 4, 5];
|
||||||
|
let text: String = cisla.iter().join(" - ");
|
||||||
|
// "1 - 2 - 3 - 4 - 5"
|
||||||
|
|
||||||
|
// Prázdny oddeľovač
|
||||||
|
let spolu: String = slova.iter().join("");
|
||||||
|
// "ahojsvetrust"
|
||||||
|
|
||||||
|
// Funguje s čímkoľvek čo implementuje Display
|
||||||
|
let floaty = vec![1.5, 2.7, 3.14];
|
||||||
|
let text: String = floaty.iter().join(", ");
|
||||||
|
// "1.5, 2.7, 3.14"
|
||||||
|
```
|
||||||
|
|
||||||
|
**Bez itertools** by si to robil cez `.collect::<Vec<String>>().join(",")` alebo ručne.
|
||||||
|
|
||||||
|
### Úlohy 3
|
||||||
|
|
||||||
|
**3a.** Máš vektor mien. Spoj ich čiarkou a medzerou do jedného reťazca.
|
||||||
|
|
||||||
|
**3b.** Máš vektor čísel 1 až 10. Spoj ich pomlčkou.
|
||||||
|
|
||||||
|
**3c.** Máš vektor štruktúr `Kniha { nazov: String }`. Spoj názvy kníh do jedného reťazca oddeleného " | ". Hint: najprv `.map()` na názvy, potom `.join()`.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Kapitola 4: counts — počítanie výskytov
|
||||||
|
|
||||||
|
```rust
|
||||||
|
use itertools::Itertools;
|
||||||
|
|
||||||
|
let slova = vec!["ahoj", "svet", "ahoj", "rust", "svet", "ahoj"];
|
||||||
|
|
||||||
|
// counts() — vráti HashMap<T, usize> s počtom výskytov
|
||||||
|
let pocty = slova.iter().counts();
|
||||||
|
// {&"ahoj": 3, &"svet": 2, &"rust": 1}
|
||||||
|
|
||||||
|
// counts_by — počítaj podľa kľúča
|
||||||
|
let text = "Hello World";
|
||||||
|
let pocty = text.chars().counts_by(|c| c.is_uppercase());
|
||||||
|
// {true: 2, false: 9} (H a W sú veľké)
|
||||||
|
```
|
||||||
|
|
||||||
|
Toto nahrádza celý ten entry().or_insert(0) vzor:
|
||||||
|
```rust
|
||||||
|
// BEZ itertools — 4 riadky
|
||||||
|
let mut pocty = HashMap::new();
|
||||||
|
for slovo in &slova {
|
||||||
|
*pocty.entry(slovo).or_insert(0) += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// S itertools — 1 riadok
|
||||||
|
let pocty = slova.iter().counts();
|
||||||
|
```
|
||||||
|
|
||||||
|
### Úlohy 4
|
||||||
|
|
||||||
|
**4a.** Máš reťazec. Spočítaj výskyt každého znaku. Použi `.chars().counts()`.
|
||||||
|
|
||||||
|
**4b.** Máš vektor štruktúr `Kniha { nazov: String, zaner: String }`. Spočítaj koľko kníh je v každom žánri. Použi `.map()` + `.counts()`.
|
||||||
|
|
||||||
|
**4c.** Máš vektor čísel. Spočítaj koľko je párnych a koľko nepárnych. Použi `.counts_by()`.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Kapitola 5: group_by — zoskupovanie
|
||||||
|
|
||||||
|
**Dôležité:** `group_by` funguje len na **už zoradených** dátach! Zoskupí po sebe idúce prvky s rovnakým kľúčom.
|
||||||
|
|
||||||
|
```rust
|
||||||
|
use itertools::Itertools;
|
||||||
|
|
||||||
|
// Dáta MUSIA byť zoradené podľa rovnakého kľúča!
|
||||||
|
let cisla = vec![1, 1, 2, 2, 2, 3, 3, 1];
|
||||||
|
|
||||||
|
// group_by zoskupí PO SEBE IDÚCE prvky
|
||||||
|
for (kluc, skupina) in &cisla.iter().group_by(|&&c| c) {
|
||||||
|
let prvky: Vec<&&i32> = skupina.collect();
|
||||||
|
println!("{}: {:?}", kluc, prvky);
|
||||||
|
}
|
||||||
|
// 1: [&&1, &&1]
|
||||||
|
// 2: [&&2, &&2, &&2]
|
||||||
|
// 3: [&&3, &&3]
|
||||||
|
// 1: [&&1] ← POZOR! Posledná 1 je v NOVEJ skupine!
|
||||||
|
```
|
||||||
|
|
||||||
|
Ak chceš všetky rovnaké spolu, musíš najprv zoradiť:
|
||||||
|
```rust
|
||||||
|
let cisla = vec![1, 3, 2, 1, 2, 3, 1];
|
||||||
|
|
||||||
|
// Najprv zoradiť, potom group_by
|
||||||
|
for (kluc, skupina) in &cisla.iter().sorted().group_by(|&&c| c) {
|
||||||
|
let pocet = skupina.count();
|
||||||
|
println!("{}: {}x", kluc, pocet);
|
||||||
|
}
|
||||||
|
// 1: 3x
|
||||||
|
// 2: 2x
|
||||||
|
// 3: 2x
|
||||||
|
```
|
||||||
|
|
||||||
|
So štruktúrami:
|
||||||
|
```rust
|
||||||
|
struct Kniha { nazov: String, zaner: String }
|
||||||
|
|
||||||
|
let knihy = vec![/* ... */];
|
||||||
|
|
||||||
|
// Zoskup podľa žánru — musíš najprv zoradiť!
|
||||||
|
let zoradene: Vec<&Kniha> = knihy.iter()
|
||||||
|
.sorted_by_key(|k| &k.zaner)
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
for (zaner, skupina) in &zoradene.iter().group_by(|k| &k.zaner) {
|
||||||
|
let knihy_v_zanri: Vec<&&&Kniha> = skupina.collect();
|
||||||
|
println!("{}: {} kníh", zaner, knihy_v_zanri.len());
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Tip:** Pre jednoduché počítanie použi radšej `.counts()` z kapitoly 4. `group_by` je užitočný keď chceš s celou skupinou niečo robiť (nie len počítať).
|
||||||
|
|
||||||
|
### Úlohy 5
|
||||||
|
|
||||||
|
**5a.** Máš vektor slov zoradený abecedne. Zoskup podľa prvého písmena a vypíš koľko slov začína na ktoré písmeno.
|
||||||
|
|
||||||
|
**5b.** Máš vektor čísel. Zoraď ich a potom zoskup rovnaké čísla. Pre každú skupinu vypíš číslo a koľkokrát sa vyskytuje.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Kapitola 6: chunk_by a chunks
|
||||||
|
|
||||||
|
### chunks — rozdeľ na kúsky pevnej veľkosti
|
||||||
|
|
||||||
|
```rust
|
||||||
|
use itertools::Itertools;
|
||||||
|
|
||||||
|
let cisla = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
|
||||||
|
|
||||||
|
// chunks(3) — skupiny po 3
|
||||||
|
for chunk in &cisla.iter().chunks(3) {
|
||||||
|
let skupina: Vec<&i32> = chunk.collect();
|
||||||
|
println!("{:?}", skupina);
|
||||||
|
}
|
||||||
|
// [1, 2, 3]
|
||||||
|
// [4, 5, 6]
|
||||||
|
// [7, 8, 9]
|
||||||
|
// [10] ← posledná skupina môže byť menšia
|
||||||
|
```
|
||||||
|
|
||||||
|
### tuple_windows — posuvné okno
|
||||||
|
|
||||||
|
```rust
|
||||||
|
let cisla = vec![1, 2, 3, 4, 5];
|
||||||
|
|
||||||
|
// Dvojice po sebe idúcich
|
||||||
|
for (a, b) in cisla.iter().tuple_windows() {
|
||||||
|
println!("{} a {}", a, b);
|
||||||
|
}
|
||||||
|
// 1 a 2
|
||||||
|
// 2 a 3
|
||||||
|
// 3 a 4
|
||||||
|
// 4 a 5
|
||||||
|
|
||||||
|
// Trojice
|
||||||
|
for (a, b, c) in cisla.iter().tuple_windows() {
|
||||||
|
println!("{}, {}, {}", a, b, c);
|
||||||
|
}
|
||||||
|
// 1, 2, 3
|
||||||
|
// 2, 3, 4
|
||||||
|
// 3, 4, 5
|
||||||
|
```
|
||||||
|
|
||||||
|
### Úlohy 6
|
||||||
|
|
||||||
|
**6a.** Máš vektor 20 študentov. Rozdeľ ich do skupín po 5. Vypíš každú skupinu.
|
||||||
|
|
||||||
|
**6b.** Máš vektor denných teplôt. Vypočítaj priemernú teplotu za každý 7-dňový úsek (chunks(7)).
|
||||||
|
|
||||||
|
**6c.** Máš vektor čísel. Použi `tuple_windows` na nájdenie všetkých párov po sebe idúcich čísel, kde druhé je väčšie ako prvé (rastúce páry).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Kapitola 7: min_set, max_set — všetky minimá/maximá
|
||||||
|
|
||||||
|
Štandardný `.min()` vráti len jedno minimum. Čo ak je ich viac?
|
||||||
|
|
||||||
|
```rust
|
||||||
|
use itertools::Itertools;
|
||||||
|
|
||||||
|
let cisla = vec![3, 1, 4, 1, 5, 1, 2];
|
||||||
|
|
||||||
|
// min_set — vráti Vec VŠETKÝCH miním
|
||||||
|
let minima: Vec<&i32> = cisla.iter().min_set();
|
||||||
|
// [&1, &1, &1] — tri jednotky
|
||||||
|
|
||||||
|
// max_set
|
||||||
|
let maxima: Vec<&i32> = cisla.iter().max_set();
|
||||||
|
// [&5]
|
||||||
|
|
||||||
|
// min_set_by_key — so štruktúrami
|
||||||
|
struct Student { meno: String, priemer: f32 }
|
||||||
|
let studenti = vec![/* ... */];
|
||||||
|
|
||||||
|
// Všetci študenti s najlepším priemerom
|
||||||
|
let najlepsi: Vec<&Student> = studenti.iter()
|
||||||
|
.min_set_by(|a, b| a.priemer.partial_cmp(&b.priemer).unwrap());
|
||||||
|
```
|
||||||
|
|
||||||
|
### Úlohy 7
|
||||||
|
|
||||||
|
**7a.** Máš vektor čísel. Nájdi všetky výskyty maximálnej hodnoty. Koľko ich je?
|
||||||
|
|
||||||
|
**7b.** Máš vektor slov. Nájdi všetky najdlhšie slová (môže ich byť viac rovnako dlhých). Použi `max_set_by_key`.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Kapitola 8: interleave a zip_eq
|
||||||
|
|
||||||
|
### interleave — striedavo z dvoch iterátorov
|
||||||
|
|
||||||
|
```rust
|
||||||
|
use itertools::Itertools;
|
||||||
|
|
||||||
|
let a = vec![1, 3, 5];
|
||||||
|
let b = vec![2, 4, 6];
|
||||||
|
|
||||||
|
let striedavo: Vec<i32> = a.into_iter().interleave(b.into_iter()).collect();
|
||||||
|
// [1, 2, 3, 4, 5, 6]
|
||||||
|
|
||||||
|
let x = vec!["a", "b", "c"];
|
||||||
|
let y = vec!["1", "2", "3"];
|
||||||
|
let mix: Vec<&str> = x.into_iter().interleave(y.into_iter()).collect();
|
||||||
|
// ["a", "1", "b", "2", "c", "3"]
|
||||||
|
```
|
||||||
|
|
||||||
|
### zip_eq — zip ktorý panicky ak rôzna dĺžka
|
||||||
|
|
||||||
|
Štandardný `.zip()` ticho skráti na kratší. `zip_eq` ti povie ak majú rôznu dĺžku:
|
||||||
|
|
||||||
|
```rust
|
||||||
|
let mena = vec!["Anna", "Boris", "Cyril"];
|
||||||
|
let veky = vec![25, 30, 22];
|
||||||
|
|
||||||
|
// Štandardný zip — OK
|
||||||
|
let pary: Vec<_> = mena.iter().zip(veky.iter()).collect();
|
||||||
|
|
||||||
|
// zip_eq — rovnaké, ale panikne ak rôzna dĺžka
|
||||||
|
let pary: Vec<_> = mena.iter().zip_eq(veky.iter()).collect();
|
||||||
|
|
||||||
|
// let veky_kratsi = vec![25, 30];
|
||||||
|
// mena.iter().zip_eq(veky_kratsi.iter()).collect(); // PANIC!
|
||||||
|
```
|
||||||
|
|
||||||
|
### Úlohy 8
|
||||||
|
|
||||||
|
**8a.** Máš vektor otázok a vektor odpovedí. Spáruj ich a vypíš "Otázka: ... → Odpoveď: ...". Použi `zip_eq` (chceš aby program spadol ak nesedia počty).
|
||||||
|
|
||||||
|
**8b.** Máš dva vektory — párne a nepárne čísla. Prelož ich striedavo do jedného vektora.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Kapitola 9: format_with a positions
|
||||||
|
|
||||||
|
### positions — indexy prvkov splňajúcich podmienku
|
||||||
|
|
||||||
|
```rust
|
||||||
|
use itertools::Itertools;
|
||||||
|
|
||||||
|
let cisla = vec![10, 25, 30, 5, 40, 15];
|
||||||
|
|
||||||
|
// Indexy prvkov > 20
|
||||||
|
let indexy: Vec<usize> = cisla.iter().positions(|c| *c > 20).collect();
|
||||||
|
// [1, 2, 4] (25 je na indexe 1, 30 na 2, 40 na 4)
|
||||||
|
```
|
||||||
|
|
||||||
|
Toto je jednoduchšie ako `.enumerate().filter().map()`:
|
||||||
|
```rust
|
||||||
|
// BEZ itertools — dlhé
|
||||||
|
let indexy: Vec<usize> = cisla.iter().enumerate()
|
||||||
|
.filter(|(_, c)| **c > 20)
|
||||||
|
.map(|(i, _)| i)
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
// S itertools — krátke
|
||||||
|
let indexy: Vec<usize> = cisla.iter().positions(|c| *c > 20).collect();
|
||||||
|
```
|
||||||
|
|
||||||
|
### Úlohy 9
|
||||||
|
|
||||||
|
**9a.** Máš vektor slov. Nájdi pozície (indexy) všetkých slov dlhších ako 5 znakov.
|
||||||
|
|
||||||
|
**9b.** Máš vektor študentov s priemerom. Nájdi indexy študentov s priemerom pod 1.5.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Kapitola 10: Kombinácie na skúške
|
||||||
|
|
||||||
|
### Vzor 1: Zoradený výpis štatistík
|
||||||
|
|
||||||
|
```rust
|
||||||
|
use itertools::Itertools;
|
||||||
|
|
||||||
|
struct Kniha { nazov: String, vydavatelstvo: String }
|
||||||
|
|
||||||
|
fn vypis_statistiky(knihy: &[Kniha]) {
|
||||||
|
// counts + sorted — zoradený výpis počtov
|
||||||
|
let pocty = knihy.iter().map(|k| &k.vydavatelstvo).counts();
|
||||||
|
for (vydavatelstvo, pocet) in pocty.iter().sorted_by_key(|(_, p)| std::cmp::Reverse(*p)) {
|
||||||
|
println!("{}: {}", vydavatelstvo, pocet);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Vzor 2: Unikátne zoradené hodnoty
|
||||||
|
|
||||||
|
```rust
|
||||||
|
fn unikatne_zanre_zoradene(knihy: &[Kniha]) -> Vec<String> {
|
||||||
|
knihy.iter()
|
||||||
|
.map(|k| k.vydavatelstvo.clone())
|
||||||
|
.unique()
|
||||||
|
.sorted()
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Vzor 3: Top N
|
||||||
|
|
||||||
|
```rust
|
||||||
|
fn top_3_studenti(studenti: &[Student]) -> Vec<&Student> {
|
||||||
|
studenti.iter()
|
||||||
|
.sorted_by(|a, b| a.priemer.partial_cmp(&b.priemer).unwrap())
|
||||||
|
.take(3)
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Vzor 4: Formátovaný výpis zoznamu
|
||||||
|
|
||||||
|
```rust
|
||||||
|
fn vypis_mena(studenti: &[Student]) -> String {
|
||||||
|
studenti.iter().map(|s| &s.meno).join(", ")
|
||||||
|
}
|
||||||
|
// "Anna, Boris, Cyril"
|
||||||
|
```
|
||||||
|
|
||||||
|
### Vzor 5: Zoskupenie a štatistiky
|
||||||
|
|
||||||
|
```rust
|
||||||
|
fn priemer_podla_triedy(studenti: &[Student]) {
|
||||||
|
for (trieda, skupina) in &studenti.iter()
|
||||||
|
.sorted_by_key(|s| &s.trieda)
|
||||||
|
.group_by(|s| &s.trieda)
|
||||||
|
{
|
||||||
|
let zoznam: Vec<&Student> = skupina.collect();
|
||||||
|
let sucet: f32 = zoznam.iter().map(|s| s.priemer).sum();
|
||||||
|
let priemer = sucet / zoznam.len() as f32;
|
||||||
|
println!("Trieda {}: priemer {:.2}", trieda, priemer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Úlohy 10
|
||||||
|
|
||||||
|
**10a.** Máš vektor `Zamestnanec { meno: String, oddelenie: String, plat: u32 }`. Napíš funkciu, ktorá:
|
||||||
|
1. Zoskupí zamestnancov podľa oddelenia
|
||||||
|
2. Pre každé oddelenie vypíše mená zoradené abecedne, spojené čiarkou
|
||||||
|
3. Oddelenia vypíše zoradené abecedne
|
||||||
|
|
||||||
|
Použi: `sorted_by_key`, `group_by`, `join`.
|
||||||
|
|
||||||
|
**10b.** Máš vektor kníh. Nájdi 5 najčastejších žánrov. Použi `counts` + `sorted_by_key` + `take`.
|
||||||
|
|
||||||
|
**10c.** Máš vektor čísel. Použi `tuple_windows` na zistenie najväčšieho rozdielu medzi dvoma po sebe idúcimi číslami.
|
||||||
|
|
||||||
|
**10d.** Máš vektor reťazcov s duplikátmi. Vyfiltruj unikátne, zoraď abecedne, spoj do jedného reťazca oddeleného " | ". Všetko jedným reťazením.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Prehľad: kedy čo z itertools
|
||||||
|
|
||||||
|
| Chcem... | Metóda |
|
||||||
|
|----------|--------|
|
||||||
|
| Zoradiť iterátor | `.sorted()`, `.sorted_by()`, `.sorted_by_key()` |
|
||||||
|
| Odstrániť duplikáty (so zachovaním poradia) | `.unique()`, `.unique_by()` |
|
||||||
|
| Spojiť do reťazca | `.join(separator)` |
|
||||||
|
| Spočítať výskyty → HashMap | `.counts()`, `.counts_by()` |
|
||||||
|
| Zoskupiť po sebe idúce | `.group_by()` (najprv sorted!) |
|
||||||
|
| Rozdeliť na kúsky | `.chunks(n)` |
|
||||||
|
| Posuvné okno | `.tuple_windows()` |
|
||||||
|
| Všetky minimá/maximá | `.min_set()`, `.max_set()` |
|
||||||
|
| Preložiť dva iterátory | `.interleave()` |
|
||||||
|
| Zip s kontrolou dĺžky | `.zip_eq()` |
|
||||||
|
| Indexy splňajúce podmienku | `.positions()` |
|
||||||
844
priprava/rust_priprava8.md
Normal file
844
priprava/rust_priprava8.md
Normal file
@@ -0,0 +1,844 @@
|
|||||||
|
# String, &str, char — krok za krokom
|
||||||
|
|
||||||
|
Každá kapitola: prečítaj, pozri príklady, urob úlohy. Až potom choď ďalej.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Kapitola 1: Čo je čo
|
||||||
|
|
||||||
|
V Ruste existujú 3 typy pre prácu s textom:
|
||||||
|
|
||||||
|
| Typ | Čo to je | Vlastní dáta? | Veľkosť |
|
||||||
|
|-----|----------|---------------|---------|
|
||||||
|
| `String` | Vlastnený, meniteľný reťazec na heape | Áno | Rastie/zmenšuje sa |
|
||||||
|
| `&str` | Referencia na kúsok textu (string slice) | Nie (len pozerá) | Fixná |
|
||||||
|
| `char` | Jeden Unicode znak | Áno | 4 bajty vždy |
|
||||||
|
|
||||||
|
```rust
|
||||||
|
// String — vlastní dáta, môžeš meniť
|
||||||
|
let mut s: String = String::from("ahoj");
|
||||||
|
s.push_str(" svet"); // OK — je mut a vlastní dáta
|
||||||
|
|
||||||
|
// &str — len referencia, nemôžeš meniť obsah
|
||||||
|
let slice: &str = "ahoj svet";
|
||||||
|
// slice.push_str("!"); // CHYBA — &str je len pohľad
|
||||||
|
|
||||||
|
// char — jeden znak
|
||||||
|
let c: char = 'a';
|
||||||
|
let emoji: char = '🦀'; // aj emoji je jeden char
|
||||||
|
```
|
||||||
|
|
||||||
|
**Analógia:**
|
||||||
|
- `String` je ako vlastný zošit — píšeš doň, pridávaš strany
|
||||||
|
- `&str` je ako pohľad cez okno na cudzí zošit — vidíš text, ale nemôžeš ho meniť
|
||||||
|
- `char` je ako jedno písmeno
|
||||||
|
|
||||||
|
### Úlohy 1
|
||||||
|
|
||||||
|
**1a.** Ktorý typ použiješ v štruktúre? Prečo?
|
||||||
|
```rust
|
||||||
|
struct Kniha {
|
||||||
|
nazov: ???, // String alebo &str?
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**1b.** Čo je zle? Oprav:
|
||||||
|
```rust
|
||||||
|
let s: &str = "ahoj";
|
||||||
|
s.push_str(" svet");
|
||||||
|
```
|
||||||
|
|
||||||
|
**1c.** Aký je typ každej premennej?
|
||||||
|
```rust
|
||||||
|
let a = "ahoj";
|
||||||
|
let b = String::from("ahoj");
|
||||||
|
let c = 'a';
|
||||||
|
let d = &b[..];
|
||||||
|
let e = b.as_str();
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Kapitola 2: Vytváranie String
|
||||||
|
|
||||||
|
Existuje veľa spôsobov ako vytvoriť String:
|
||||||
|
|
||||||
|
```rust
|
||||||
|
// 1. String::from
|
||||||
|
let s = String::from("ahoj");
|
||||||
|
|
||||||
|
// 2. .to_string() — funguje na čomkoľvek s Display
|
||||||
|
let s = "ahoj".to_string();
|
||||||
|
let s = 42.to_string(); // "42"
|
||||||
|
let s = 3.14.to_string(); // "3.14"
|
||||||
|
let s = true.to_string(); // "true"
|
||||||
|
|
||||||
|
// 3. String::new() — prázdny
|
||||||
|
let s = String::new(); // ""
|
||||||
|
|
||||||
|
// 4. format! — ako println!, ale vráti String
|
||||||
|
let meno = "Anna";
|
||||||
|
let vek = 25;
|
||||||
|
let s = format!("{} má {} rokov", meno, vek);
|
||||||
|
// "Anna má 25 rokov"
|
||||||
|
|
||||||
|
// 5. .to_owned() — z &str na String
|
||||||
|
let slice: &str = "ahoj";
|
||||||
|
let owned: String = slice.to_owned();
|
||||||
|
|
||||||
|
// 6. .into() — Rust odvodí konverziu
|
||||||
|
let s: String = "ahoj".into();
|
||||||
|
```
|
||||||
|
|
||||||
|
**Ktorý použiť:**
|
||||||
|
- `String::from("...")` alebo `"...".to_string()` — oboje je rovnaké, použi čo sa ti páči
|
||||||
|
- `format!()` — keď skladáš z viacerých častí
|
||||||
|
- `String::new()` — keď budeš pridávať postupne
|
||||||
|
|
||||||
|
### Úlohy 2
|
||||||
|
|
||||||
|
**2a.** Vytvor String z čísla `42`, z boolu `false`, z float `3.14`. Vypíš ich.
|
||||||
|
|
||||||
|
**2b.** Máš premenné `meno: &str` a `vek: u32`. Vytvor String vo formáte `"Meno: Anna, Vek: 25"` pomocou `format!`.
|
||||||
|
|
||||||
|
**2c.** Vytvor prázdny String a postupne do neho pridaj 3 slová (použi `push_str`). Výsledok vypíš.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Kapitola 3: Konverzie medzi String a &str
|
||||||
|
|
||||||
|
```rust
|
||||||
|
// &str → String (3 spôsoby, všetky robia to isté)
|
||||||
|
let slice: &str = "ahoj";
|
||||||
|
let owned1: String = slice.to_string();
|
||||||
|
let owned2: String = slice.to_owned();
|
||||||
|
let owned3: String = String::from(slice);
|
||||||
|
|
||||||
|
// String → &str (2 spôsoby)
|
||||||
|
let owned: String = String::from("ahoj");
|
||||||
|
let slice1: &str = &owned; // automatická dereferencia
|
||||||
|
let slice2: &str = owned.as_str(); // explicitné
|
||||||
|
|
||||||
|
// String → &str v parametroch funkcie — automaticky!
|
||||||
|
fn prijmi_str(s: &str) {
|
||||||
|
println!("{}", s);
|
||||||
|
}
|
||||||
|
let owned = String::from("ahoj");
|
||||||
|
prijmi_str(&owned); // String sa automaticky konvertuje na &str
|
||||||
|
prijmi_str("ahoj"); // &str funguje priamo
|
||||||
|
```
|
||||||
|
|
||||||
|
**Zlaté pravidlo pre funkcie:**
|
||||||
|
- Parametre píš ako `&str` — prijmeš aj String aj &str
|
||||||
|
- Návratové hodnoty a polia v štruktúrach píš ako `String` — vlastníš dáta
|
||||||
|
|
||||||
|
```rust
|
||||||
|
// DOBRÉ — parameter &str prijme oboje
|
||||||
|
fn pozdrav(meno: &str) -> String {
|
||||||
|
format!("Ahoj, {}!", meno)
|
||||||
|
}
|
||||||
|
pozdrav("Anna"); // &str → OK
|
||||||
|
pozdrav(&String::from("Boris")); // &String → OK
|
||||||
|
pozdrav(&"Cyril".to_string()); // &String → OK
|
||||||
|
|
||||||
|
// ZLÉ — parameter String núti volajúceho robiť konverziu
|
||||||
|
fn pozdrav_zle(meno: String) -> String {
|
||||||
|
format!("Ahoj, {}!", meno)
|
||||||
|
}
|
||||||
|
// pozdrav_zle("Anna"); // CHYBA — &str nie je String
|
||||||
|
pozdrav_zle("Anna".to_string()); // musíš konvertovať
|
||||||
|
```
|
||||||
|
|
||||||
|
### Úlohy 3
|
||||||
|
|
||||||
|
**3a.** Napíš funkciu `dlzka(text: &str) -> usize` ktorá vráti dĺžku. Zavolaj ju s `&str` aj so `String`.
|
||||||
|
|
||||||
|
**3b.** Napíš funkciu `opakuj(text: &str, n: usize) -> String` ktorá vráti text zopakovaný n-krát.
|
||||||
|
|
||||||
|
**3c.** Čo je zle? Oprav:
|
||||||
|
```rust
|
||||||
|
fn prvych_5(text: String) -> String {
|
||||||
|
text[..5].to_string()
|
||||||
|
}
|
||||||
|
prvych_5("ahoj svet");
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Kapitola 4: Modifikácia String
|
||||||
|
|
||||||
|
String je meniteľný. Tu sú všetky spôsoby ako ho meniť:
|
||||||
|
|
||||||
|
### Pridávanie
|
||||||
|
|
||||||
|
```rust
|
||||||
|
let mut s = String::from("ahoj");
|
||||||
|
|
||||||
|
// push_str — pridaj &str na koniec
|
||||||
|
s.push_str(" svet"); // "ahoj svet"
|
||||||
|
|
||||||
|
// push — pridaj jeden char
|
||||||
|
s.push('!'); // "ahoj svet!"
|
||||||
|
|
||||||
|
// + operátor — spája String + &str (konzumuje prvý!)
|
||||||
|
let a = String::from("ahoj");
|
||||||
|
let b = String::from(" svet");
|
||||||
|
let c = a + &b; // c = "ahoj svet", a JE ZKONZUMOVANÝ!
|
||||||
|
// println!("{}", a); // CHYBA — a bolo presunuté do c
|
||||||
|
|
||||||
|
// format! — bezpečná konkatenácia (nekonzumuje nič)
|
||||||
|
let a = String::from("ahoj");
|
||||||
|
let b = String::from("svet");
|
||||||
|
let c = format!("{} {}", a, b); // c = "ahoj svet"
|
||||||
|
println!("{}", a); // OK — a stále existuje
|
||||||
|
```
|
||||||
|
|
||||||
|
### Mazanie
|
||||||
|
|
||||||
|
```rust
|
||||||
|
let mut s = String::from("ahoj svet");
|
||||||
|
|
||||||
|
// clear — vymaž všetko
|
||||||
|
s.clear(); // ""
|
||||||
|
|
||||||
|
let mut s = String::from("ahoj svet");
|
||||||
|
|
||||||
|
// truncate — skráť na N bajtov
|
||||||
|
s.truncate(4); // "ahoj"
|
||||||
|
|
||||||
|
let mut s = String::from("ahoj");
|
||||||
|
|
||||||
|
// pop — odstráň posledný char, vráti Option<char>
|
||||||
|
let posledny = s.pop(); // Some('j'), s = "aho"
|
||||||
|
```
|
||||||
|
|
||||||
|
### Nahradenie
|
||||||
|
|
||||||
|
```rust
|
||||||
|
let s = String::from("ahoj svet ahoj");
|
||||||
|
|
||||||
|
// replace — nahraď všetky výskyty (vráti nový String)
|
||||||
|
let novy = s.replace("ahoj", "čau");
|
||||||
|
// "čau svet čau"
|
||||||
|
|
||||||
|
// replacen — nahraď len prvých N výskytov
|
||||||
|
let novy = s.replacen("ahoj", "čau", 1);
|
||||||
|
// "čau svet ahoj"
|
||||||
|
```
|
||||||
|
|
||||||
|
**Dôležité:** `replace` vracia nový String, nemení pôvodný.
|
||||||
|
|
||||||
|
### Úlohy 4
|
||||||
|
|
||||||
|
**4a.** Vytvor String `"Rust je super"`. Pridaj na koniec `" jazyk!"`. Pridaj na koniec `'🦀'`. Vypíš výsledok.
|
||||||
|
|
||||||
|
**4b.** Máš String `"ahoj_svet_rust"`. Nahraď všetky `_` medzerou. Vypíš.
|
||||||
|
|
||||||
|
**4c.** Máš String. Postupne z neho popuj znaky kým nie je prázdny. Každý vypíš.
|
||||||
|
|
||||||
|
**4d.** Čo je zle? Oprav (2 spôsoby):
|
||||||
|
```rust
|
||||||
|
let a = String::from("ahoj");
|
||||||
|
let b = String::from(" svet");
|
||||||
|
let c = a + &b;
|
||||||
|
println!("{}", a); // chyba!
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Kapitola 5: char — jeden znak
|
||||||
|
|
||||||
|
`char` v Ruste je 4 bajty a reprezentuje jeden Unicode bod (nie bajt!).
|
||||||
|
|
||||||
|
```rust
|
||||||
|
let c: char = 'a';
|
||||||
|
let emoji: char = '🦀';
|
||||||
|
let slovak: char = 'ž';
|
||||||
|
|
||||||
|
// Kontroly
|
||||||
|
c.is_alphabetic(); // true — je písmeno?
|
||||||
|
c.is_numeric(); // false — je číslica?
|
||||||
|
c.is_alphanumeric(); // true — písmeno alebo číslica?
|
||||||
|
c.is_uppercase(); // false
|
||||||
|
c.is_lowercase(); // true
|
||||||
|
c.is_whitespace(); // false — je medzera/tab/newline?
|
||||||
|
c.is_ascii(); // true — je ASCII (0-127)?
|
||||||
|
|
||||||
|
// Konverzia veľkosť
|
||||||
|
c.to_uppercase(); // iterátor! nie char (lebo 'ß' → "SS")
|
||||||
|
c.to_lowercase(); // iterátor!
|
||||||
|
c.to_ascii_uppercase(); // char — len pre ASCII znaky
|
||||||
|
c.to_ascii_lowercase(); // char
|
||||||
|
|
||||||
|
// char → String
|
||||||
|
let s: String = c.to_string(); // "a"
|
||||||
|
let s: String = String::from(c); // "a"
|
||||||
|
|
||||||
|
// char → u32 (Unicode code point)
|
||||||
|
let kod: u32 = c as u32; // 97
|
||||||
|
|
||||||
|
// u32 → char (ak je platný Unicode)
|
||||||
|
let c: Option<char> = char::from_u32(97); // Some('a')
|
||||||
|
```
|
||||||
|
|
||||||
|
**Dôležité o to_uppercase/to_lowercase:**
|
||||||
|
```rust
|
||||||
|
// to_uppercase vráti iterátor, nie char!
|
||||||
|
// Lebo niektoré znaky sa mapujú na viac znakov: ß → SS
|
||||||
|
let velke: String = 'a'.to_uppercase().collect(); // "A"
|
||||||
|
let velke: String = 'ß'.to_uppercase().collect(); // "SS"
|
||||||
|
|
||||||
|
// Pre jednoduché ASCII použi to_ascii_uppercase — vráti char
|
||||||
|
let velke: char = 'a'.to_ascii_uppercase(); // 'A'
|
||||||
|
```
|
||||||
|
|
||||||
|
### Úlohy 5
|
||||||
|
|
||||||
|
**5a.** Napíš funkciu `je_samohláska(c: char) -> bool` — true pre a, e, i, o, u (aj veľké). Použi `to_ascii_lowercase()` a `matches!` alebo porovnávanie.
|
||||||
|
|
||||||
|
**5b.** Napíš funkciu `pocet_cifier(text: &str) -> usize` — koľko znakov v texte sú číslice. Použi `.chars()` a `.is_numeric()`.
|
||||||
|
|
||||||
|
**5c.** Napíš funkciu `velkymi(text: &str) -> String` — celý text veľkými písmenami. Použi `.chars()`, `.to_ascii_uppercase()`, `.collect()`.
|
||||||
|
|
||||||
|
**5d.** Čo vráti?
|
||||||
|
```rust
|
||||||
|
println!("{}", 'A'.is_uppercase());
|
||||||
|
println!("{}", '5'.is_numeric());
|
||||||
|
println!("{}", ' '.is_whitespace());
|
||||||
|
println!("{}", 'ž'.is_ascii());
|
||||||
|
println!("{}", 'ž'.is_alphabetic());
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Kapitola 6: Iterácia cez znaky — chars()
|
||||||
|
|
||||||
|
String v Ruste je UTF-8. Jeden znak môže byť 1–4 bajty. Preto nemôžeš indexovať `s[0]` — nevieš koľko bajtov má znak.
|
||||||
|
|
||||||
|
```rust
|
||||||
|
let text = "ahoj";
|
||||||
|
|
||||||
|
// chars() — iterátor cez char hodnoty
|
||||||
|
for c in text.chars() {
|
||||||
|
println!("{}", c); // a, h, o, j
|
||||||
|
}
|
||||||
|
|
||||||
|
// Počet znakov
|
||||||
|
let pocet: usize = text.chars().count(); // 4
|
||||||
|
|
||||||
|
// Do Vec<char>
|
||||||
|
let znaky: Vec<char> = text.chars().collect();
|
||||||
|
// ['a', 'h', 'o', 'j']
|
||||||
|
|
||||||
|
// N-tý znak
|
||||||
|
let druhy: Option<char> = text.chars().nth(1); // Some('h')
|
||||||
|
|
||||||
|
// Prvý znak
|
||||||
|
let prvy: Option<char> = text.chars().next(); // Some('a')
|
||||||
|
|
||||||
|
// Posledný znak
|
||||||
|
let posledny: Option<char> = text.chars().last(); // Some('j')
|
||||||
|
```
|
||||||
|
|
||||||
|
**Pozor na .len() vs .chars().count():**
|
||||||
|
```rust
|
||||||
|
let text = "žaba";
|
||||||
|
println!("{}", text.len()); // 5 (bajtov! 'ž' = 2 bajty)
|
||||||
|
println!("{}", text.chars().count()); // 4 (znakov)
|
||||||
|
|
||||||
|
// Pre čisto ASCII texty sú rovnaké
|
||||||
|
let text = "ahoj";
|
||||||
|
println!("{}", text.len()); // 4
|
||||||
|
println!("{}", text.chars().count()); // 4
|
||||||
|
```
|
||||||
|
|
||||||
|
### chars() s iterátorovými metódami
|
||||||
|
|
||||||
|
```rust
|
||||||
|
let text = "Ahoj Svet 123";
|
||||||
|
|
||||||
|
// filter — len písmená
|
||||||
|
let pismena: String = text.chars().filter(|c| c.is_alphabetic()).collect();
|
||||||
|
// "AhojSvet"
|
||||||
|
|
||||||
|
// map — na veľké
|
||||||
|
let velke: String = text.chars().map(|c| c.to_ascii_uppercase()).collect();
|
||||||
|
// "AHOJ SVET 123"
|
||||||
|
|
||||||
|
// any — obsahuje číslicu?
|
||||||
|
let ma_cislo: bool = text.chars().any(|c| c.is_numeric());
|
||||||
|
// true
|
||||||
|
|
||||||
|
// all — sú všetky písmená?
|
||||||
|
let vsetky_pismena: bool = text.chars().all(|c| c.is_alphabetic());
|
||||||
|
// false
|
||||||
|
|
||||||
|
// enumerate — index + znak
|
||||||
|
for (i, c) in text.chars().enumerate() {
|
||||||
|
println!("{}: {}", i, c);
|
||||||
|
}
|
||||||
|
|
||||||
|
// take — prvých N znakov
|
||||||
|
let prvych_4: String = text.chars().take(4).collect();
|
||||||
|
// "Ahoj"
|
||||||
|
|
||||||
|
// skip — preskoč prvých N znakov
|
||||||
|
let od_5: String = text.chars().skip(5).collect();
|
||||||
|
// "Svet 123"
|
||||||
|
```
|
||||||
|
|
||||||
|
### Úlohy 6
|
||||||
|
|
||||||
|
**6a.** Napíš funkciu `prevrat(text: &str) -> String` — obráti text. Použi `.chars().rev().collect()`.
|
||||||
|
|
||||||
|
**6b.** Napíš funkciu `je_palindrom(text: &str) -> bool` — true ak sa text rovná sám sebe pozadu. Ignoruj veľkosť písmen.
|
||||||
|
|
||||||
|
**6c.** Napíš funkciu `censuruj(text: &str, zakazane: &[char]) -> String` — nahraď zakázané znaky hviezdičkou `'*'`. Použi `.chars().map().collect()`.
|
||||||
|
|
||||||
|
**6d.** Napíš funkciu `prvych_n_znakov(text: &str, n: usize) -> String`. Použi `.chars().take(n).collect()`.
|
||||||
|
|
||||||
|
**6e.** Napíš funkciu `pocet_slov(text: &str) -> usize`. Použi `.split_whitespace().count()`.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Kapitola 7: Rozdeľovanie reťazcov — split, lines, split_whitespace
|
||||||
|
|
||||||
|
### split_whitespace — rozdeľ podľa medzier
|
||||||
|
|
||||||
|
```rust
|
||||||
|
let text = " ahoj svet rust ";
|
||||||
|
|
||||||
|
let slova: Vec<&str> = text.split_whitespace().collect();
|
||||||
|
// ["ahoj", "svet", "rust"] — medzery na okrajoch a duplikáty ignorované
|
||||||
|
```
|
||||||
|
|
||||||
|
### split — rozdeľ podľa oddeľovača
|
||||||
|
|
||||||
|
```rust
|
||||||
|
let text = "anna,boris,cyril";
|
||||||
|
|
||||||
|
// Podľa znaku
|
||||||
|
let mena: Vec<&str> = text.split(',').collect();
|
||||||
|
// ["anna", "boris", "cyril"]
|
||||||
|
|
||||||
|
// Podľa reťazca
|
||||||
|
let text = "ahoj--svet--rust";
|
||||||
|
let casti: Vec<&str> = text.split("--").collect();
|
||||||
|
// ["ahoj", "svet", "rust"]
|
||||||
|
|
||||||
|
// splitn — maximálne N častí
|
||||||
|
let text = "a:b:c:d:e";
|
||||||
|
let casti: Vec<&str> = text.splitn(3, ':').collect();
|
||||||
|
// ["a", "b", "c:d:e"] — rozdelí len na prvých 2 dvojbodkách
|
||||||
|
```
|
||||||
|
|
||||||
|
### lines — rozdeľ podľa riadkov
|
||||||
|
|
||||||
|
```rust
|
||||||
|
let text = "prvý riadok\ndruhý riadok\ntretí riadok";
|
||||||
|
|
||||||
|
for riadok in text.lines() {
|
||||||
|
println!("{}", riadok);
|
||||||
|
}
|
||||||
|
// prvý riadok
|
||||||
|
// druhý riadok
|
||||||
|
// tretí riadok
|
||||||
|
```
|
||||||
|
|
||||||
|
### Úlohy 7
|
||||||
|
|
||||||
|
**7a.** Máš CSV riadok `"Anna,25,Bratislava"`. Rozdeľ ho na časti. Vypíš meno, vek, mesto.
|
||||||
|
|
||||||
|
**7b.** Napíš funkciu `pocet_slov(text: &str) -> usize`. Použi `split_whitespace`.
|
||||||
|
|
||||||
|
**7c.** Máš viacriadkový text. Nájdi najdlhší riadok. Použi `.lines()` a `.max_by_key()`.
|
||||||
|
|
||||||
|
**7d.** Máš cestu `"/home/user/docs/file.txt"`. Rozdeľ podľa `/`. Vypíš posledný kúsok (filename).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Kapitola 8: Hľadanie v reťazcoch
|
||||||
|
|
||||||
|
```rust
|
||||||
|
let text = "Ahoj svet, ahoj Rust!";
|
||||||
|
|
||||||
|
// contains — obsahuje podreťazec?
|
||||||
|
text.contains("svet"); // true
|
||||||
|
text.contains("Python"); // false
|
||||||
|
|
||||||
|
// starts_with / ends_with
|
||||||
|
text.starts_with("Ahoj"); // true
|
||||||
|
text.ends_with("!"); // true
|
||||||
|
text.ends_with("Rust"); // false (končí na "!")
|
||||||
|
|
||||||
|
// find — index prvého výskytu (v bajtoch!)
|
||||||
|
text.find("svet"); // Some(5)
|
||||||
|
text.find("Python"); // None
|
||||||
|
|
||||||
|
// rfind — od konca
|
||||||
|
text.rfind("ahoj"); // Some(11)
|
||||||
|
|
||||||
|
// matches — iterátor cez všetky výskyty
|
||||||
|
let pocet = text.matches("ahoj").count(); // 1 (case-sensitive!)
|
||||||
|
let pocet = text.to_lowercase().matches("ahoj").count(); // 2
|
||||||
|
```
|
||||||
|
|
||||||
|
### Úlohy 8
|
||||||
|
|
||||||
|
**8a.** Napíš funkciu `obsahuje_cislicu(text: &str) -> bool` — true ak text obsahuje aspoň jednu číslicu. Použi `.chars().any()`.
|
||||||
|
|
||||||
|
**8b.** Napíš funkciu `pocet_vyskytu(text: &str, hladany: &str) -> usize`. Použi `.matches().count()`.
|
||||||
|
|
||||||
|
**8c.** Napíš funkciu `zacina_velkym(text: &str) -> bool` — true ak prvý znak je veľké písmeno.
|
||||||
|
|
||||||
|
**8d.** Máš vektor reťazcov. Vyfiltruj len tie, ktoré obsahujú slovo "rust" (case-insensitive).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Kapitola 9: Trimovanie a padding
|
||||||
|
|
||||||
|
### trim — odstráň biele znaky z okrajov
|
||||||
|
|
||||||
|
```rust
|
||||||
|
let text = " ahoj svet \n";
|
||||||
|
|
||||||
|
text.trim(); // "ahoj svet"
|
||||||
|
text.trim_start(); // "ahoj svet \n"
|
||||||
|
text.trim_end(); // " ahoj svet"
|
||||||
|
|
||||||
|
// trim_matches — odstráň konkrétne znaky
|
||||||
|
let text = "---ahoj---";
|
||||||
|
text.trim_matches('-'); // "ahoj"
|
||||||
|
|
||||||
|
let text = "***ahoj***svet***";
|
||||||
|
text.trim_matches('*'); // "ahoj***svet" (len okraje!)
|
||||||
|
```
|
||||||
|
|
||||||
|
### Padding / zarovnanie (nie metóda, ale format!)
|
||||||
|
|
||||||
|
```rust
|
||||||
|
let meno = "Anna";
|
||||||
|
|
||||||
|
// Zarovnanie vpravo (šírka 10)
|
||||||
|
let s = format!("{:>10}", meno); // " Anna"
|
||||||
|
|
||||||
|
// Zarovnanie vľavo
|
||||||
|
let s = format!("{:<10}", meno); // "Anna "
|
||||||
|
|
||||||
|
// Na stred
|
||||||
|
let s = format!("{:^10}", meno); // " Anna "
|
||||||
|
|
||||||
|
// S vlastným znakom
|
||||||
|
let s = format!("{:*>10}", meno); // "******Anna"
|
||||||
|
let s = format!("{:-^10}", meno); // "---Anna---"
|
||||||
|
```
|
||||||
|
|
||||||
|
### Úlohy 9
|
||||||
|
|
||||||
|
**9a.** Máš vstup od používateľa `" ahoj \n"`. Očisti ho trimom. Potom over, či je "ahoj".
|
||||||
|
|
||||||
|
**9b.** Máš vektor mien rôznej dĺžky. Vypíš ich zarovnané vpravo na šírku 15 znakov:
|
||||||
|
```
|
||||||
|
Anna
|
||||||
|
Boris
|
||||||
|
Cyril
|
||||||
|
```
|
||||||
|
|
||||||
|
**9c.** Napíš funkciu `ocisti(text: &str) -> String` — trim + nahraď viacnásobné medzery jednou. Hint: `split_whitespace().collect::<Vec<&str>>().join(" ")`.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Kapitola 10: Slicing — &str z časti String
|
||||||
|
|
||||||
|
Môžeš vziať kúsok reťazca ako &str. Ale **pozor** — indexy sú v bajtoch, nie znakoch!
|
||||||
|
|
||||||
|
```rust
|
||||||
|
let text = "ahoj svet";
|
||||||
|
|
||||||
|
// Slice podľa rozsahu bajtov
|
||||||
|
let slice: &str = &text[0..4]; // "ahoj"
|
||||||
|
let slice: &str = &text[5..]; // "svet"
|
||||||
|
let slice: &str = &text[..4]; // "ahoj"
|
||||||
|
|
||||||
|
// NEBEZPEČNÉ pre non-ASCII!
|
||||||
|
let text = "žaba";
|
||||||
|
// &text[0..1] // PANIC! 'ž' je 2 bajty, toto by rozdelilo uprostred znaku!
|
||||||
|
// &text[0..2] // OK — "ž"
|
||||||
|
```
|
||||||
|
|
||||||
|
**Bezpečný spôsob pre ľubovoľný text:**
|
||||||
|
```rust
|
||||||
|
// Použi chars() namiesto slicingu
|
||||||
|
fn prvy_znak(text: &str) -> Option<char> {
|
||||||
|
text.chars().next()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn prvych_n(text: &str, n: usize) -> String {
|
||||||
|
text.chars().take(n).collect()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn od_znaku_n(text: &str, n: usize) -> String {
|
||||||
|
text.chars().skip(n).collect()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn podretazec(text: &str, od: usize, do_: usize) -> String {
|
||||||
|
text.chars().skip(od).take(do_ - od).collect()
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Kedy je slice bezpečný:**
|
||||||
|
- Ak vieš, že text je čistý ASCII (anglická abeceda, čísla)
|
||||||
|
- Ak index získaš z `.find()` (ten vracia bajtový index)
|
||||||
|
|
||||||
|
```rust
|
||||||
|
let text = "ahoj svet rust";
|
||||||
|
if let Some(pos) = text.find("svet") {
|
||||||
|
let od_svet: &str = &text[pos..]; // "svet rust" — bezpečné, find vrátil správny index
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Úlohy 10
|
||||||
|
|
||||||
|
**10a.** Máš ASCII text `"Hello World"`. Vyber prvých 5 znakov slicingom. Vyber posledných 5.
|
||||||
|
|
||||||
|
**10b.** Napíš funkciu `bezpecne_prvych_n(text: &str, n: usize) -> String` — vráti prvých N znakov bez paniki (aj pre non-ASCII).
|
||||||
|
|
||||||
|
**10c.** Máš text. Nájdi pozíciu prvej medzery pomocou `.find(' ')`. Ak existuje, vráť prvé slovo ako &str slice:
|
||||||
|
```rust
|
||||||
|
fn prve_slovo(text: &str) -> &str
|
||||||
|
```
|
||||||
|
|
||||||
|
**10d.** Prečo toto panikne? Ako to opravíš?
|
||||||
|
```rust
|
||||||
|
let text = "café";
|
||||||
|
let slice = &text[0..4];
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Kapitola 11: Parsovanie — z reťazca na iné typy
|
||||||
|
|
||||||
|
```rust
|
||||||
|
// &str / String → číslo (.parse())
|
||||||
|
let cislo: i32 = "42".parse().unwrap(); // 42
|
||||||
|
let cislo: f64 = "3.14".parse().unwrap(); // 3.14
|
||||||
|
let cislo: Result<i32, _> = "nie_cislo".parse(); // Err(...)
|
||||||
|
|
||||||
|
// Bezpečné parsovanie
|
||||||
|
let vstup = "42";
|
||||||
|
match vstup.parse::<i32>() {
|
||||||
|
Ok(n) => println!("Číslo: {}", n),
|
||||||
|
Err(_) => println!("Nie je číslo"),
|
||||||
|
}
|
||||||
|
|
||||||
|
// Alebo s .ok()
|
||||||
|
let cislo: Option<i32> = vstup.parse().ok();
|
||||||
|
|
||||||
|
// číslo → String
|
||||||
|
let text: String = 42.to_string();
|
||||||
|
let text: String = format!("{}", 42);
|
||||||
|
|
||||||
|
// bool
|
||||||
|
let b: bool = "true".parse().unwrap(); // true
|
||||||
|
let b: bool = "false".parse().unwrap(); // false
|
||||||
|
```
|
||||||
|
|
||||||
|
### Úlohy 11
|
||||||
|
|
||||||
|
**11a.** Napíš funkciu `parsuj_cisla(text: &str) -> Vec<i32>` — text obsahuje čísla oddelené čiarkami (`"1,2,3,4,5"`). Rozdeľ a sparsuj. Ignoruj neplatné hodnoty.
|
||||||
|
|
||||||
|
**11b.** Napíš funkciu `parsuj_csv_riadok(riadok: &str) -> Option<(String, u32, f64)>`:
|
||||||
|
Vstup: `"Anna,25,1.5"` → `Some(("Anna".to_string(), 25, 1.5))`
|
||||||
|
Ak parsovanie zlyhá → None.
|
||||||
|
|
||||||
|
**11c.** Máš vstup od používateľa (String). Trim ho, parsuj na u32. Ak sa nepodarí, vyskúšaj f64. Ak ani to, vráť chybu.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Kapitola 12: Pokročilé operácie
|
||||||
|
|
||||||
|
### repeat — opakuj reťazec
|
||||||
|
|
||||||
|
```rust
|
||||||
|
let s = "ha".repeat(3); // "hahaha"
|
||||||
|
let s = "-".repeat(20); // "--------------------"
|
||||||
|
```
|
||||||
|
|
||||||
|
### to_lowercase / to_uppercase
|
||||||
|
|
||||||
|
```rust
|
||||||
|
let text = "Ahoj Svet";
|
||||||
|
let male: String = text.to_lowercase(); // "ahoj svet"
|
||||||
|
let velke: String = text.to_uppercase(); // "AHOJ SVET"
|
||||||
|
|
||||||
|
// Porovnanie case-insensitive
|
||||||
|
fn rovnake_ci(a: &str, b: &str) -> bool {
|
||||||
|
a.to_lowercase() == b.to_lowercase()
|
||||||
|
}
|
||||||
|
rovnake_ci("Ahoj", "AHOJ"); // true
|
||||||
|
```
|
||||||
|
|
||||||
|
### char_indices — indexy aj znaky
|
||||||
|
|
||||||
|
```rust
|
||||||
|
let text = "žaba";
|
||||||
|
|
||||||
|
// char_indices dáva (bajtový_index, char)
|
||||||
|
for (i, c) in text.char_indices() {
|
||||||
|
println!("bajt {}: {}", i, c);
|
||||||
|
}
|
||||||
|
// bajt 0: ž
|
||||||
|
// bajt 2: a (ž zabrala 2 bajty!)
|
||||||
|
// bajt 3: b
|
||||||
|
// bajt 4: a
|
||||||
|
```
|
||||||
|
|
||||||
|
### Collect medzi typmi
|
||||||
|
|
||||||
|
```rust
|
||||||
|
// Vec<char> → String
|
||||||
|
let znaky = vec!['a', 'h', 'o', 'j'];
|
||||||
|
let text: String = znaky.into_iter().collect();
|
||||||
|
// "ahoj"
|
||||||
|
|
||||||
|
// Vec<&str> → String (s oddeľovačom)
|
||||||
|
let slova = vec!["ahoj", "svet"];
|
||||||
|
let text: String = slova.join(" ");
|
||||||
|
// "ahoj svet"
|
||||||
|
|
||||||
|
// Vec<String> → String (s oddeľovačom)
|
||||||
|
let slova: Vec<String> = vec!["ahoj".into(), "svet".into()];
|
||||||
|
let text: String = slova.join(", ");
|
||||||
|
// "ahoj, svet"
|
||||||
|
|
||||||
|
// Iterátor &str → String
|
||||||
|
let text: String = ["ahoj", "svet"].iter().copied().collect::<Vec<&str>>().join(" ");
|
||||||
|
|
||||||
|
// S itertools je jednoduchšie:
|
||||||
|
// use itertools::Itertools;
|
||||||
|
// let text = ["ahoj", "svet"].iter().join(" ");
|
||||||
|
```
|
||||||
|
|
||||||
|
### Úlohy 12
|
||||||
|
|
||||||
|
**12a.** Napíš funkciu `oddelovac(sirka: usize) -> String` — vráti riadok pomlčiek danej šírky.
|
||||||
|
|
||||||
|
**12b.** Napíš funkciu `kapitalizuj(text: &str) -> String` — prvé písmeno veľké, zvyšok malé. Hint: `.chars().next()` pre prvé, `.chars().skip(1)` pre zvyšok.
|
||||||
|
|
||||||
|
**12c.** Napíš funkciu `snake_to_camel(text: &str) -> String` — preveď `"ahoj_svet_rust"` na `"AhojSvetRust"`. Hint: split podľa `_`, každé slovo kapitalizuj, spoj.
|
||||||
|
|
||||||
|
**12d.** Napíš funkciu `je_platny_email(text: &str) -> bool`:
|
||||||
|
- Obsahuje presne jednu `@`
|
||||||
|
- Pred `@` je aspoň 1 znak
|
||||||
|
- Za `@` je aspoň 3 znaky
|
||||||
|
- Za `@` obsahuje `.`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Kapitola 13: Vzory zo skúšky
|
||||||
|
|
||||||
|
### Vzor 1: Display pre štruktúru/enum
|
||||||
|
|
||||||
|
```rust
|
||||||
|
use std::fmt;
|
||||||
|
|
||||||
|
enum Stav { Novy, Aktivny, Dokonceny }
|
||||||
|
|
||||||
|
impl fmt::Display for Stav {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
match self {
|
||||||
|
Stav::Novy => write!(f, "Nový"),
|
||||||
|
Stav::Aktivny => write!(f, "Aktívny"),
|
||||||
|
Stav::Dokonceny => write!(f, "Dokončený"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Uloha { nazov: String, stav: Stav }
|
||||||
|
|
||||||
|
impl fmt::Display for Uloha {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
write!(f, "{} [{}]", self.nazov, self.stav)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Výstup: "Upratovanie [Nový]"
|
||||||
|
```
|
||||||
|
|
||||||
|
### Vzor 2: Obesenec — zobrazenie skrytého slova
|
||||||
|
|
||||||
|
```rust
|
||||||
|
fn zobraz_slovo(slovo: &str, uhadnute: &HashSet<char>) -> String {
|
||||||
|
slovo.chars().map(|c| {
|
||||||
|
if uhadnute.contains(&c) { c } else { '_' }
|
||||||
|
}).collect()
|
||||||
|
}
|
||||||
|
// zobraz_slovo("ahoj", &{'a', 'o'}) → "a_o_"
|
||||||
|
```
|
||||||
|
|
||||||
|
### Vzor 3: Parsovanie vstupu od používateľa
|
||||||
|
|
||||||
|
```rust
|
||||||
|
fn nacitaj_cislo() -> Option<u32> {
|
||||||
|
let mut vstup = String::new();
|
||||||
|
std::io::stdin().read_line(&mut vstup).ok()?;
|
||||||
|
vstup.trim().parse().ok()
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Vzor 4: CSV / JSON parsovanie
|
||||||
|
|
||||||
|
```rust
|
||||||
|
fn parsuj_knihu(riadok: &str) -> Option<Kniha> {
|
||||||
|
let casti: Vec<&str> = riadok.split(',').collect();
|
||||||
|
if casti.len() != 3 { return None; }
|
||||||
|
let rok: u16 = casti[2].trim().parse().ok()?;
|
||||||
|
Some(Kniha {
|
||||||
|
nazov: casti[0].trim().to_string(),
|
||||||
|
autor: casti[1].trim().to_string(),
|
||||||
|
rok,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Úlohy 13
|
||||||
|
|
||||||
|
**13a.** Implementuj `Display` pre enum `Priorita { Nizka, Stredna, Vysoka }` — výstup: "Nízka", "Stredná", "Vysoká".
|
||||||
|
|
||||||
|
**13b.** Implementuj `Display` pre štruktúru `Zamestnanec { meno: String, pozicia: String, plat: u32 }` vo formáte `"Anna (Programátor) - 3000€"`.
|
||||||
|
|
||||||
|
**13c.** Napíš funkciu, ktorá načíta riadok z stdin, trimne ho a vráti. Ak je prázdny po trime, vráti None:
|
||||||
|
```rust
|
||||||
|
fn nacitaj_riadok() -> Option<String>
|
||||||
|
```
|
||||||
|
|
||||||
|
**13d.** Napíš funkciu, ktorá sparsuje text `"meno:vek:mesto"` na tuple:
|
||||||
|
```rust
|
||||||
|
fn parsuj(text: &str) -> Option<(String, u32, String)>
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Prehľad konverzií
|
||||||
|
|
||||||
|
```
|
||||||
|
&str ──.to_string()──→ String
|
||||||
|
&str ──.to_owned()───→ String
|
||||||
|
&str ──String::from()─→ String
|
||||||
|
|
||||||
|
String ──&──────────→ &str
|
||||||
|
String ──.as_str()──→ &str
|
||||||
|
|
||||||
|
char ──.to_string()─→ String
|
||||||
|
char ──String::from()→ String
|
||||||
|
|
||||||
|
&str ──.chars()─────→ Iterator<char>
|
||||||
|
String ──.chars()───→ Iterator<char>
|
||||||
|
|
||||||
|
Iterator<char> ──.collect()──→ String
|
||||||
|
Vec<char> ──.iter().collect()→ String
|
||||||
|
|
||||||
|
&str ──.parse::<T>()──→ Result<T, Error>
|
||||||
|
T ──.to_string()───────→ String (ak T: Display)
|
||||||
|
|
||||||
|
&str ──.as_bytes()────→ &[u8]
|
||||||
|
```
|
||||||
1031
priprava/rust_priprava9.md
Normal file
1031
priprava/rust_priprava9.md
Normal file
File diff suppressed because it is too large
Load Diff
123
riesenie1/Cargo.lock
generated
Normal file
123
riesenie1/Cargo.lock
generated
Normal file
@@ -0,0 +1,123 @@
|
|||||||
|
# This file is automatically @generated by Cargo.
|
||||||
|
# It is not intended for manual editing.
|
||||||
|
version = 4
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "either"
|
||||||
|
version = "1.15.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "itertools"
|
||||||
|
version = "0.14.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "2b192c782037fadd9cfa75548310488aabdbf3d2da73885b31bd0abd03351285"
|
||||||
|
dependencies = [
|
||||||
|
"either",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "itoa"
|
||||||
|
version = "1.0.17"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "92ecc6618181def0457392ccd0ee51198e065e016d1d527a7ac1b6dc7c1f09d2"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "memchr"
|
||||||
|
version = "2.8.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "proc-macro2"
|
||||||
|
version = "1.0.106"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934"
|
||||||
|
dependencies = [
|
||||||
|
"unicode-ident",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "quote"
|
||||||
|
version = "1.0.44"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "21b2ebcf727b7760c461f091f9f0f539b77b8e87f2fd88131e7f1b433b3cece4"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "riesenie1"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"itertools",
|
||||||
|
"serde",
|
||||||
|
"serde_json",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "serde"
|
||||||
|
version = "1.0.228"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e"
|
||||||
|
dependencies = [
|
||||||
|
"serde_core",
|
||||||
|
"serde_derive",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "serde_core"
|
||||||
|
version = "1.0.228"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad"
|
||||||
|
dependencies = [
|
||||||
|
"serde_derive",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "serde_derive"
|
||||||
|
version = "1.0.228"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "serde_json"
|
||||||
|
version = "1.0.149"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "83fc039473c5595ace860d8c4fafa220ff474b3fc6bfdb4293327f1a37e94d86"
|
||||||
|
dependencies = [
|
||||||
|
"itoa",
|
||||||
|
"memchr",
|
||||||
|
"serde",
|
||||||
|
"serde_core",
|
||||||
|
"zmij",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "syn"
|
||||||
|
version = "2.0.117"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"unicode-ident",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "unicode-ident"
|
||||||
|
version = "1.0.24"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "zmij"
|
||||||
|
version = "1.0.21"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa"
|
||||||
9
riesenie1/Cargo.toml
Normal file
9
riesenie1/Cargo.toml
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
[package]
|
||||||
|
name = "riesenie1"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2024"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
itertools = "0.14.0"
|
||||||
|
serde = { version = "1.0.228", features = ["derive"] }
|
||||||
|
serde_json = "1.0.149"
|
||||||
118
riesenie1/src/lib.rs
Normal file
118
riesenie1/src/lib.rs
Normal file
@@ -0,0 +1,118 @@
|
|||||||
|
// src/lib.rs
|
||||||
|
use std::fmt;
|
||||||
|
use std::fs::File;
|
||||||
|
use std::fs;
|
||||||
|
use std::collections::HashMap;
|
||||||
|
use std::io::Write;
|
||||||
|
|
||||||
|
#[derive(Debug, Default, serde::Serialize, serde::Deserialize)]
|
||||||
|
pub struct Kniha {
|
||||||
|
autori: Vec<String>,
|
||||||
|
nazov: String,
|
||||||
|
vydavatelstvo: String,
|
||||||
|
zaner: String,
|
||||||
|
pocet_stran: usize,
|
||||||
|
isbn: String,
|
||||||
|
rok_vydania: String,
|
||||||
|
pozicana: bool,
|
||||||
|
stav_knihy: Stav,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for Kniha {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
write!(f, "({:#?}, {}, {}, {}, {}, {}, {}, {}, {:#?})",
|
||||||
|
self.autori,
|
||||||
|
self.nazov,
|
||||||
|
self.vydavatelstvo,
|
||||||
|
self.zaner,
|
||||||
|
self.pocet_stran,
|
||||||
|
self.isbn,
|
||||||
|
self.rok_vydania,
|
||||||
|
self.pozicana,
|
||||||
|
self.stav_knihy,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Default, serde::Serialize, serde::Deserialize, PartialEq)]
|
||||||
|
pub enum Stav {
|
||||||
|
#[default]
|
||||||
|
Nova,
|
||||||
|
Pouzivana,
|
||||||
|
Poskodena,
|
||||||
|
Vyradena
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for Stav {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
match self {
|
||||||
|
Stav::Nova => write!(f, "Nova"),
|
||||||
|
Stav::Pouzivana => write!(f, "Pouzivana"),
|
||||||
|
Stav::Poskodena => write!(f, "Poskodena"),
|
||||||
|
Stav::Vyradena => write!(f, "Vyradena"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Default, serde::Serialize, serde::Deserialize)]
|
||||||
|
pub struct Kniznica {
|
||||||
|
knihy: Vec<Kniha>
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Kniznica {
|
||||||
|
pub fn nacitaj_zo_suboru(r: &std::path::PathBuf) -> Option<Kniznica> {
|
||||||
|
let d: String = std::fs::read_to_string(r).ok()?;
|
||||||
|
let r: Option<Kniznica> = serde_json::from_str(&d).ok()?;
|
||||||
|
r
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn uloz_do_suboru(&self, z: &std::path::PathBuf) -> bool {
|
||||||
|
let Ok(f) = File::create(z) else{
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
serde_json::to_writer_pretty(f, &self).is_ok()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn pridaj_knihu(&mut self, k: Kniha) -> Result<(), ()> {
|
||||||
|
if self.knihy.iter().map(|x| x.isbn.clone()).any(|y| y == k.isbn) {
|
||||||
|
return Err(());
|
||||||
|
}
|
||||||
|
self.knihy.push(k);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn odstran_knihu(&mut self, r: &str) -> Result<Kniha, ()> {
|
||||||
|
let Some(k) = self.knihy.iter().position(|x| x.isbn == r) else {
|
||||||
|
return Err(());
|
||||||
|
};
|
||||||
|
let t = self.knihy.remove(k);
|
||||||
|
Ok(t)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn daj_knihu_podla_isbn(&self, i: &str) -> Option<&Kniha> {
|
||||||
|
self.knihy.iter().find(|x| x.isbn == i)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn daj_knihy_autora(&self, a: &str) -> Vec<&Kniha> {
|
||||||
|
self.knihy.iter().filter(|y| y.autori.contains(&a.to_string())).collect()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn daj_knihy_podla_stavu(&self, s: Stav) -> Vec<&Kniha> {
|
||||||
|
self.knihy.iter().filter(|x| x.stav_knihy == s).collect()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn vypis_vydavatelstva_a_pocet_knih(&self) {
|
||||||
|
let mut h: HashMap<String, usize> = HashMap::new();
|
||||||
|
for x in self.knihy.iter() {
|
||||||
|
h.entry(x.vydavatelstvo.clone()).and_modify(|x| *x += 1).or_insert(1);
|
||||||
|
}
|
||||||
|
// self.knihy.iter().counts();
|
||||||
|
for y in h.iter() {
|
||||||
|
println!("{}: {} knih", y.0, y.1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn vypis_knihy_daneho_zanru(&self, zk: &str) {
|
||||||
|
self.knihy.iter().filter(|&x| x.zaner == zk).map(|x| println!("{:#?}", x));
|
||||||
|
}
|
||||||
|
}
|
||||||
3
riesenie1/src/main.rs
Normal file
3
riesenie1/src/main.rs
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
fn main() {
|
||||||
|
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user