io
This commit is contained in:
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.
|
||||
Reference in New Issue
Block a user