# serde a serde_json — krok za krokom Každá kapitola: prečítaj, pozri príklady, urob úlohy. Až potom choď ďalej. `Cargo.toml`: ```toml [dependencies] serde = { version = "1", features = ["derive"] } serde_json = "1" ``` ```rust use serde::{Serialize, Deserialize}; ``` --- ## Kapitola 1: Čo je serde serde je framework na **serializáciu** a **deserializáciu** dát v Ruste. - **Serializácia** = Rust štruktúra → nejaký formát (JSON, TOML, YAML...) - **Deserializácia** = nejaký formát → Rust štruktúra serde samotné nerobí nič s JSON. Je to len systém traitov. Konkrétny formát zabezpečuje knižnica ako `serde_json`. ``` Rust štruktúra ──Serialize──→ JSON string JSON string ──Deserialize──→ Rust štruktúra ``` serde funguje cez dva traity: - `Serialize` — štruktúra sa vie premeniť na dáta - `Deserialize` — dáta sa vedia premeniť na štruktúru Neimplementuješ ich ručne. Použiješ `#[derive()]`: ```rust use serde::{Serialize, Deserialize}; #[derive(Serialize, Deserialize)] struct Osoba { meno: String, vek: u32, } ``` Toto je všetko. Teraz Osoba vie byť serializovaná a deserializovaná. ### Úlohy 1 **1a.** Čo je serializácia? Čo je deserializácia? Povedz to vlastnými slovami. **1b.** Aký je rozdiel medzi `serde` a `serde_json`? **1c.** Napíš štruktúru `Kniha` s poľami `nazov: String`, `autor: String`, `rok: u16`. Pridaj derive pre Serialize a Deserialize. --- ## Kapitola 2: Serialize — štruktúra → JSON ```rust use serde::{Serialize, Deserialize}; #[derive(Serialize, Deserialize)] struct Osoba { meno: String, vek: u32, email: String, } fn main() { let anna = Osoba { meno: "Anna".to_string(), vek: 25, email: "anna@mail.sk".to_string(), }; // to_string — kompaktný JSON (jeden riadok) let json: String = serde_json::to_string(&anna).unwrap(); println!("{}", json); // {"meno":"Anna","vek":25,"email":"anna@mail.sk"} // to_string_pretty — pekne formátovaný JSON let json_pretty: String = serde_json::to_string_pretty(&anna).unwrap(); println!("{}", json_pretty); // { // "meno": "Anna", // "vek": 25, // "email": "anna@mail.sk" // } } ``` **Návratový typ:** `serde_json::to_string` vracia `Result`. Preto `.unwrap()` alebo `?` alebo `.ok()`. **Čo sa serializuje:** - `String` → `"text"` - čísla → čísla - `bool` → `true`/`false` - `Vec` → `[...]` - `Option` → hodnota alebo `null` - `HashMap` → `{...}` objekt - vnorené štruktúry → vnorené objekty ```rust #[derive(Serialize, Deserialize)] struct Kniznica { nazov: String, knihy: Vec, // → JSON pole otvorena: bool, // → true/false poznamka: Option, // → "text" alebo null } ``` ### Úlohy 2 **2a.** Vytvor štruktúru `Auto` s poľami `znacka: String`, `rok: u16`, `cena: f64`. Serializuj jedno auto do JSON. Vypíš kompaktne aj pretty. **2b.** Vytvor vektor 3 áut. Serializuj celý vektor do JSON. Aký formát má výstup? **2c.** Vytvor štruktúru `Garaz` s poľom `auta: Vec`. Serializuj garáž s 2 autami. Ako vyzerá JSON? **2d.** Čo sa stane ak pole je `Option` a je `None`? Serializuj a pozri. --- ## Kapitola 3: Deserialize — JSON → štruktúra ```rust use serde::{Serialize, Deserialize}; #[derive(Serialize, Deserialize, Debug)] struct Osoba { meno: String, vek: u32, } fn main() { let json = r#"{"meno":"Anna","vek":25}"#; // from_str — JSON string → štruktúra let osoba: Osoba = serde_json::from_str(json).unwrap(); println!("{:?}", osoba); // Osoba { meno: "Anna", vek: 25 } // Typ musíš uviesť (Rust nevie aká štruktúra) let osoba: Result = serde_json::from_str(json); match osoba { Ok(o) => println!("Meno: {}", o.meno), Err(e) => println!("Chyba: {}", e), } } ``` **`r#"..."#`** — raw string literal. Netreba escapovať úvodzovky. Veľmi užitočné pre JSON. **Čo sa stane ak JSON nesedí?** ```rust // Chýba pole let json = r#"{"meno":"Anna"}"#; let vysledok: Result = serde_json::from_str(json); // Err — chýba pole "vek" // Zlý typ let json = r#"{"meno":"Anna","vek":"dvadsatpat"}"#; let vysledok: Result = serde_json::from_str(json); // Err — vek nie je číslo // Extra pole — OK! serde ho ignoruje let json = r#"{"meno":"Anna","vek":25,"extra":"niečo"}"#; let osoba: Osoba = serde_json::from_str(json).unwrap(); // OK — extra pole sa ignoruje ``` ### Úlohy 3 **3a.** Máš JSON: ```json {"nazov":"Duna","autor":"Frank Herbert","rok":1965} ``` Deserializuj ho do štruktúry `Kniha`. Vypíš názov a rok. **3b.** Máš JSON pole: ```json [{"nazov":"A","rok":2000},{"nazov":"B","rok":2010}] ``` Deserializuj ho do `Vec`. Vypíš počet kníh. **3c.** Čo sa stane ak JSON obsahuje pole, ktoré štruktúra nemá? Vyskúšaj. **3d.** Čo sa stane ak JSON-u chýba pole, ktoré štruktúra vyžaduje? Vyskúšaj. --- ## Kapitola 4: Enumy v serde ```rust use serde::{Serialize, Deserialize}; // Jednoduchý enum (bez dát) — serializuje sa ako string #[derive(Serialize, Deserialize, Debug)] enum Farba { Cervena, Modra, Zelena, } let json = serde_json::to_string(&Farba::Cervena).unwrap(); // "Cervena" let farba: Farba = serde_json::from_str(r#""Modra""#).unwrap(); // Farba::Modra ``` ```rust // Enum s dátami — komplexnejší JSON #[derive(Serialize, Deserialize, Debug)] enum Sprava { Text(String), Cislo(i32), Pozicia { x: f64, y: f64 }, Prazdna, } let json = serde_json::to_string(&Sprava::Text("ahoj".into())).unwrap(); // {"Text":"ahoj"} let json = serde_json::to_string(&Sprava::Pozicia { x: 1.0, y: 2.0 }).unwrap(); // {"Pozicia":{"x":1.0,"y":2.0}} let json = serde_json::to_string(&Sprava::Prazdna).unwrap(); // "Prazdna" ``` Jednoduchý enum (bez dát) v štruktúre: ```rust #[derive(Serialize, Deserialize, Debug)] enum Stav { Nova, Pouzivana, Poskodena, Vyradena, } #[derive(Serialize, Deserialize, Debug)] struct Kniha { nazov: String, stav: Stav, } let kniha = Kniha { nazov: "Duna".into(), stav: Stav::Nova, }; let json = serde_json::to_string_pretty(&kniha).unwrap(); // { // "nazov": "Duna", // "stav": "Nova" // } ``` ### Úlohy 4 **4a.** Vytvor enum `Priorita` s hodnotami `Nizka, Stredna, Vysoka`. Serializuj každú hodnotu. Aký JSON produkujú? **4b.** Vytvor štruktúru `Uloha { nazov: String, priorita: Priorita }`. Serializuj jednu úlohu. Deserializuj JSON späť. **4c.** Vytvor enum s dátami: ```rust enum Odpoved { Spravna, Nespravna { pokus: u32 }, Nevyplnena, } ``` Serializuj každú variantu a pozri aký JSON generujú. --- ## Kapitola 5: Súborový I/O — načítanie a uloženie Toto je na **každej** skúške. Vždy rovnaký vzor. ### Uloženie do súboru ```rust use std::fs; use serde::{Serialize, Deserialize}; #[derive(Serialize, Deserialize, Default)] struct Kniznica { knihy: Vec, } impl Kniznica { fn uloz_do_suboru(&self, cesta: &std::path::PathBuf) -> bool { // 1. Serializuj na JSON string let Ok(json) = serde_json::to_string_pretty(&self) else { return false; }; // 2. Zapíš do súboru fs::write(cesta, json).is_ok() } } ``` ### Načítanie zo súboru ```rust impl Kniznica { fn nacitaj_zo_suboru(cesta: &std::path::PathBuf) -> Option { // 1. Prečítaj súbor let raw = fs::read_to_string(cesta).ok()?; // 2. Deserializuj JSON string na štruktúru serde_json::from_str(&raw).ok() } } ``` **Prečo `.ok()?`:** - `fs::read_to_string` vracia `Result` - `.ok()` ho premení na `Option` (zahodí chybu) - `?` vráti `None` ak bol výsledok `None`, inak rozbalí hodnotu **Prečo posledný riadok nemá `?`:** - `serde_json::from_str` vracia `Result` - `.ok()` ho premení na `Option` - Toto je posledný výraz funkcie, takže sa priamo vráti ### Kompletný vzor (toto si zapamätaj naspamäť) ```rust use std::fs; use std::path::PathBuf; use serde::{Serialize, Deserialize}; #[derive(Serialize, Deserialize, Default)] struct MojaStruktura { data: Vec, } impl MojaStruktura { fn nacitaj_zo_suboru(cesta: &PathBuf) -> Option { let raw = fs::read_to_string(cesta).ok()?; serde_json::from_str(&raw).ok() } 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() } } ``` Toto sa na skúške nikdy nemení. Len názov štruktúry sa zmení. ### Úlohy 5 **5a.** Napíš `nacitaj_zo_suboru` a `uloz_do_suboru` pre: ```rust #[derive(Serialize, Deserialize, Default)] struct Adresar { kontakty: Vec, } #[derive(Serialize, Deserialize, Clone)] struct Kontakt { meno: String, telefon: String, } ``` **5b.** Napíš program, ktorý: 1. Vytvorí `Adresar` s 2 kontaktmi 2. Uloží ho do `"adresar.json"` 3. Načíta ho späť 4. Vypíše počet kontaktov **5c.** Čo sa stane keď: - Súbor neexistuje a voláš `nacitaj_zo_suboru`? - Súbor obsahuje neplatný JSON? - Súbor obsahuje platný JSON ale inej štruktúry? Vyskúšaj všetky 3 prípady. --- ## Kapitola 6: Derive traity — čo kedy pridať Na skúške musíš vedieť aké derive traity pridať. Tu je prehľad: ### Serialize a Deserialize ```rust #[derive(Serialize, Deserialize)] ``` **Kedy:** Vždy keď štruktúra/enum sa má ukladať do JSON alebo načítať z JSON. **Požiadavka:** Všetky polia musia tiež implementovať Serialize/Deserialize. Štandardné typy (String, i32, Vec, HashMap, Option...) to majú. ### Default ```rust #[derive(Default)] ``` **Kedy:** Keď chceš vytvoriť inštanciu s defaultnými hodnotami. ```rust #[derive(Default, Serialize, Deserialize)] struct Kniznica { knihy: Vec, // default = prázdny Vec } // Použitie: let kniznica = Kniznica::default(); // knihy = [] // Na skúške typicky: let kniznica = Kniznica::nacitaj_zo_suboru(&cesta) .unwrap_or_default(); // ak súbor neexistuje, prázdna knižnica ``` Defaultné hodnoty: - `String` → `""` - `Vec` → `vec![]` - `i32, u32, f64...` → `0` - `bool` → `false` - `Option` → `None` ### Clone ```rust #[derive(Clone)] ``` **Kedy:** Keď potrebuješ kópiu štruktúry. Toto potrebuješ ak: - Vraciaš štruktúru z vektora (nie referenciu) - Ukladáš kópiu niekam - Voláš `.clone()` na štruktúre ### Debug ```rust #[derive(Debug)] ``` **Kedy:** Keď chceš `println!("{:?}", struktura)`. Užitočné pri debugovaní. ### PartialEq ```rust #[derive(PartialEq)] ``` **Kedy:** Keď chceš porovnávať `==` a `!=` medzi inštanciami. ```rust #[derive(PartialEq)] enum Stav { Nova, Pouzivana } let a = Stav::Nova; let b = Stav::Nova; println!("{}", a == b); // true — funguje vďaka PartialEq ``` ### Kombinované — typický vzor zo skúšky ```rust // Enum — zvyčajne všetko #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] enum Stav { Nova, Pouzivana, Poskodena, Vyradena, } // Vnorená štruktúra — Serialize, Deserialize, Clone #[derive(Debug, Clone, Serialize, Deserialize)] struct Kniha { nazov: String, stav: Stav, } // Hlavná štruktúra — Serialize, Deserialize, Default #[derive(Debug, Serialize, Deserialize, Default)] struct Kniznica { knihy: Vec, } ``` ### Úlohy 6 **6a.** Zadanie hovorí: ``` Enum Stav: Nova, Pouzivana, Poskodena, Vyradena Požadované traity: Default, Display, Serialize, Deserialize, PartialEq Default vráti hodnotu Nova ``` Implementuj to. Pozor: `Default` a `Display` sa nedajú derive automaticky pre enum s vlastnou default hodnotou — musíš ich implementovať ručne. **6b.** Prečo knižnica (hlavná štruktúra) potrebuje `Default` ale kniha (vnorená štruktúra) nie? **6c.** Kedy potrebuješ `Clone` na štruktúre? Uveď 2 príklady kódu, kde by bez Clone kompilácia zlyhala. --- ## Kapitola 7: Option v serde `Option` sa serializuje špeciálne: ```rust #[derive(Serialize, Deserialize, Debug)] struct Profil { meno: String, prezyvka: Option, vek: Option, } // Some → hodnota let profil = Profil { meno: "Anna".into(), prezyvka: Some("Anka".into()), vek: Some(25), }; // {"meno":"Anna","prezyvka":"Anka","vek":25} // None → null let profil = Profil { meno: "Boris".into(), prezyvka: None, vek: None, }; // {"meno":"Boris","prezyvka":null,"vek":null} ``` **Deserializácia:** ```rust // Pole chýba v JSON → None (ak je Option) let json = r#"{"meno":"Cyril"}"#; // BEZ špeciálnej konfigurácie: CHYBA! serde čaká všetky polia. // S atribútom skip_serializing_if + default: #[derive(Serialize, Deserialize, Debug)] struct Profil { meno: String, #[serde(default)] // ak chýba v JSON, použi Default (None pre Option) prezyvka: Option, #[serde(default)] vek: Option, } // Teraz: {"meno":"Cyril"} → Profil { meno: "Cyril", prezyvka: None, vek: None } ``` Na skúške väčšinou nemusíš riešiť `#[serde(default)]` — JSON vždy obsahuje všetky polia. Ale je dobré vedieť, že to existuje. ### Úlohy 7 **7a.** Vytvor štruktúru `Student { meno: String, email: Option, vek: u32 }`. Serializuj študenta s emailom aj bez. Porovnaj JSON. **7b.** Deserializuj tento JSON na štruktúru: ```json {"meno":"Anna","email":null,"vek":25} ``` Čo bude hodnota poľa `email`? **7c.** Máš Vec. Vyfiltruj len tých, ktorí majú email (email.is_some()). Serializuj výsledok. --- ## Kapitola 8: HashMap a Vec v serde ### Vec → JSON pole ```rust #[derive(Serialize, Deserialize)] struct Trieda { nazov: String, studenti: Vec, } let trieda = Trieda { nazov: "4.A".into(), studenti: vec!["Anna".into(), "Boris".into()], }; // { // "nazov": "4.A", // "studenti": ["Anna", "Boris"] // } ``` ### HashMap → JSON objekt ```rust use std::collections::HashMap; #[derive(Serialize, Deserialize)] struct Slovnik { preklady: HashMap, } let mut preklady = HashMap::new(); preklady.insert("dog".into(), "pes".into()); preklady.insert("cat".into(), "mačka".into()); let slovnik = Slovnik { preklady }; // { // "preklady": { // "dog": "pes", // "cat": "mačka" // } // } ``` **Dôležité:** HashMap kľúče musia byť String (alebo čísla) v JSON. JSON nepodporuje iné typy kľúčov. ### Vnorené štruktúry ```rust #[derive(Serialize, Deserialize)] struct Adresa { ulica: String, mesto: String, } #[derive(Serialize, Deserialize)] struct Osoba { meno: String, adresa: Adresa, // vnorený objekt telefony: Vec, // pole } // { // "meno": "Anna", // "adresa": { // "ulica": "Hlavná 1", // "mesto": "Bratislava" // }, // "telefony": ["+421 900 000 000"] // } ``` ### Úlohy 8 **8a.** Vytvor štruktúru `SpravcaHry` s poľom `slovnik: HashMap>` (kategória → slová). Serializuj s 2 kategóriami, každá s 3 slovami. Pozri JSON. **8b.** Deserializuj tento JSON: ```json { "meno": "Knižnica", "knihy": [ {"nazov": "Duna", "rok": 1965}, {"nazov": "Hobbit", "rok": 1937} ] } ``` Aké štruktúry potrebuješ? **8c.** Máš `HashMap>`. Serializuj ho priamo (nie v štruktúre). Čo je výsledok? --- ## Kapitola 9: serde_json::Value — dynamický JSON Niekedy nevieš aký tvar bude mať JSON. Alebo ti stačí prísť len k jednej hodnote. ```rust use serde_json::Value; let json = r#"{"meno":"Anna","vek":25,"aktívna":true}"#; // Parsuj do Value — generického JSON typu let v: Value = serde_json::from_str(json).unwrap(); // Prístup k hodnotám cez ["kľúč"] println!("{}", v["meno"]); // "Anna" println!("{}", v["vek"]); // 25 println!("{}", v["aktívna"]); // true println!("{}", v["neexistuje"]); // null // Konverzia na Rust typy let meno: Option<&str> = v["meno"].as_str(); // Some("Anna") let vek: Option = v["vek"].as_u64(); // Some(25) let aktivna: Option = v["aktívna"].as_bool(); // Some(true) ``` **Typy v Value:** ```rust enum Value { Null, Bool(bool), Number(Number), String(String), Array(Vec), Object(Map), } ``` **Vytváranie JSON dynamicky:** ```rust use serde_json::json; // json! makro — vytvor Value rýchlo let v = json!({ "meno": "Anna", "vek": 25, "zaujmy": ["šach", "čítanie"], "adresa": { "mesto": "Bratislava" } }); println!("{}", v["zaujmy"][0]); // "šach" ``` ### Úlohy 9 **9a.** Máš neznámy JSON. Parsuj ho do `Value`. Skontroluj či obsahuje kľúč "meno". Ak áno, vypíš hodnotu. **9b.** Vytvor JSON pomocou `json!` makra s vnoreným objektom a poľom. Serializuj ho do pretty stringu. **9c.** Kedy použiješ `Value` a kedy vlastnú štruktúru? --- ## Kapitola 10: Atribúty — #[serde(...)] serde má atribúty, ktorými ovládaš ako sa serializuje/deserializuje. ### rename — premenuj pole ```rust #[derive(Serialize, Deserialize)] struct Osoba { #[serde(rename = "full_name")] meno: String, vek: u32, } // {"full_name":"Anna","vek":25} ``` ### rename_all — premenuj všetky polia ```rust #[derive(Serialize, Deserialize)] #[serde(rename_all = "camelCase")] struct Osoba { cele_meno: String, datum_narodenia: String, } // {"celeMeno":"Anna","datumNarodenia":"2000-01-01"} // Ďalšie možnosti: // "snake_case" → cele_meno // "camelCase" → celeMeno // "PascalCase" → CeleMeno // "SCREAMING_SNAKE_CASE" → CELE_MENO // "kebab-case" → cele-meno ``` ### skip — vynechaj pole ```rust #[derive(Serialize, Deserialize)] struct Osoba { meno: String, #[serde(skip)] // toto pole sa neserializuje ani nedeserializuje docasne_data: String, } ``` ### default — default hodnota ak chýba v JSON ```rust #[derive(Serialize, Deserialize)] struct Config { #[serde(default)] port: u16, // ak chýba → 0 #[serde(default = "default_host")] host: String, // ak chýba → "localhost" } fn default_host() -> String { "localhost".to_string() } ``` ### deny_unknown_fields — zakáž extra polia ```rust #[derive(Serialize, Deserialize)] #[serde(deny_unknown_fields)] struct Osoba { meno: String, vek: u32, } // {"meno":"Anna","vek":25,"extra":"niečo"} → CHYBA! ``` ### Úlohy 10 **10a.** Máš API, ktoré vracia JSON s camelCase kľúčmi: ```json {"firstName":"Anna","lastName":"Nováková","dateOfBirth":"2000-01-01"} ``` Napíš Rust štruktúru, ktorá toto deserializuje. Použi `#[serde(rename_all = "camelCase")]`. **10b.** Máš štruktúru s poľom `heslo: String`, ktoré sa nesmie objaviť v JSON. Použi `#[serde(skip)]`. **10c.** Máš config štruktúru. Niektoré polia sú voliteľné a majú default hodnotu. Použi `#[serde(default)]`. --- ## Kapitola 11: Chybové stavy a bezpečné spracovanie ### Result z serde_json Obe hlavné funkcie vracajú Result: ```rust // Serializácia — skoro nikdy nezlyhá (len ak typ nie je serializovateľný) let vysledok: Result = serde_json::to_string(&data); // Deserializácia — zlyhá často (neplatný JSON, zlá štruktúra) let vysledok: Result = serde_json::from_str(json); ``` ### Vzory spracovania chýb ```rust // 1. unwrap — program spadne ak chyba (len pre testovacie účely!) let data: MojTyp = serde_json::from_str(json).unwrap(); // 2. ? — propaguj chybu nahor fn spracuj(json: &str) -> Result { let data: MojTyp = serde_json::from_str(json)?; Ok(data) } // 3. .ok() — zahoď chybu, vráť Option let data: Option = serde_json::from_str(json).ok(); // 4. .ok()? — v funkcii vracajúcej Option (TOTO JE VZOR ZO SKÚŠKY) fn nacitaj(cesta: &PathBuf) -> Option { let raw = fs::read_to_string(cesta).ok()?; serde_json::from_str(&raw).ok() } // 5. match — keď chceš reagovať na chybu match serde_json::from_str::(json) { Ok(data) => println!("OK: {:?}", data), Err(e) => println!("Chyba: {}", e), } // 6. let..else — keď chceš hodnotu alebo early return let Ok(json) = serde_json::to_string_pretty(&self) else { return false; }; ``` ### Úlohy 11 **11a.** Napíš funkciu `bezpecne_parsuj(json: &str) -> Option` — vráti None pri akejkoľvek chybe. **11b.** Napíš funkciu `parsuj_alebo_default(json: &str) -> Kniznica` — ak sa nepodarí parsovať, vráti prázdnu knižnicu. Použi `.unwrap_or_default()`. **11c.** Napíš funkciu `nacitaj_a_pridaj(cesta: &PathBuf, kniha: Kniha) -> bool`: 1. Načítaj knižnicu zo súboru (ak neexistuje, vytvor prázdnu) 2. Pridaj knihu 3. Ulož späť 4. Vráť true ak sa podarilo --- ## Kapitola 12: Praktické vzory zo skúšky ### Vzor 1: Kompletný skúškový vzor (lib.rs) ```rust use serde::{Serialize, Deserialize}; use std::collections::HashMap; use std::fs; use std::path::PathBuf; #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] 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, } impl Kniznica { pub fn nacitaj_zo_suboru(cesta: &PathBuf) -> Option { 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_knihu(&mut self, kniha: Kniha) -> Result<(), ()> { if self.knihy.iter().any(|k| k.nazov == kniha.nazov) { return Err(()); } self.knihy.push(kniha); Ok(()) } // ... ďalšie metódy } ``` ### Vzor 2: main.rs s načítaním ```rust use std::path::PathBuf; fn main() { let cesta = PathBuf::from("kniznica.json"); // Načítaj alebo vytvor novú let mut kniznica = Kniznica::nacitaj_zo_suboru(&cesta) .unwrap_or_default(); // Urob niečo let kniha = Kniha { nazov: "Duna".into(), autor: "Herbert".into(), rok: 1965, stav: Stav::Nova, }; let _ = kniznica.pridaj_knihu(kniha); // Ulož kniznica.uloz_do_suboru(&cesta); } ``` ### Vzor 3: SpravcaHry s HashMap (Obesenec) ```rust #[derive(Debug, Serialize, Deserialize, Default)] pub struct SpravcaHry { pub slovnik: HashMap>, } impl SpravcaHry { pub fn nacitaj_zo_suboru(cesta: &PathBuf) -> Option { 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_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(()) } } ``` JSON pre SpravcaHry: ```json { "slovnik": { "zvierata": ["pes", "mačka", "kôň"], "jedlo": ["pizza", "burger", "šalát"] } } ``` ### Úlohy 12 **12a.** Implementuj kompletný vzor pre **Milionár** zo skúšky: ``` Štruktúra Odpoved: text (String), je_spravna (bool) Štruktúra Otazka: text (String), odpovede (Vec) Štruktúra Milionar: otazky (Vec) + nacitaj_zo_suboru, uloz_do_suboru ``` Pridaj správne derive traity. Vytvor testovacie dáta, ulož do JSON, načítaj späť. **12b.** Vytvor JSON ručne (v .json súbore alebo v kóde cez `r#"..."#`). Potom ho načítaj do tvojej štruktúry. Over, že všetky hodnoty sedia. **12c.** Napíš funkciu, ktorá načíta ľubovoľný JSON ako `Value`, overí či obsahuje kľúč `"verzia"`, a ak áno, vypíše jeho hodnotu.