24 KiB
serde a serde_json — krok za krokom
Každá kapitola: prečítaj, pozri príklady, urob úlohy. Až potom choď ďalej.
Cargo.toml:
[dependencies]
serde = { version = "1", features = ["derive"] }
serde_json = "1"
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átaDeserialize— dáta sa vedia premeniť na štruktúru
Neimplementuješ ich ručne. Použiješ #[derive()]:
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
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<String, serde_json::Error>. Preto .unwrap() alebo ? alebo .ok().
Čo sa serializuje:
String→"text"- čísla → čísla
bool→true/falseVec<T>→[...]Option<T>→ hodnota alebonullHashMap<String, T>→{...}objekt- vnorené štruktúry → vnorené objekty
#[derive(Serialize, Deserialize)]
struct Kniznica {
nazov: String,
knihy: Vec<Kniha>, // → JSON pole
otvorena: bool, // → true/false
poznamka: Option<String>, // → "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<Auto>. Serializuj garáž s 2 autami. Ako vyzerá JSON?
2d. Čo sa stane ak pole je Option<String> a je None? Serializuj a pozri.
Kapitola 3: Deserialize — JSON → štruktúra
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<Osoba, _> = 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í?
// Chýba pole
let json = r#"{"meno":"Anna"}"#;
let vysledok: Result<Osoba, _> = serde_json::from_str(json);
// Err — chýba pole "vek"
// Zlý typ
let json = r#"{"meno":"Anna","vek":"dvadsatpat"}"#;
let vysledok: Result<Osoba, _> = 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:
{"nazov":"Duna","autor":"Frank Herbert","rok":1965}
Deserializuj ho do štruktúry Kniha. Vypíš názov a rok.
3b. Máš JSON pole:
[{"nazov":"A","rok":2000},{"nazov":"B","rok":2010}]
Deserializuj ho do Vec<Kniha>. 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
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
// 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:
#[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:
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
use std::fs;
use serde::{Serialize, Deserialize};
#[derive(Serialize, Deserialize, Default)]
struct Kniznica {
knihy: Vec<Kniha>,
}
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
impl Kniznica {
fn nacitaj_zo_suboru(cesta: &std::path::PathBuf) -> Option<Kniznica> {
// 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_stringvraciaResult<String, io::Error>.ok()ho premení naOption<String>(zahodí chybu)?vrátiNoneak bol výsledokNone, inak rozbalí hodnotu
Prečo posledný riadok nemá ?:
serde_json::from_strvraciaResult<T, Error>.ok()ho premení naOption<T>- Toto je posledný výraz funkcie, takže sa priamo vráti
Kompletný vzor (toto si zapamätaj naspamäť)
use std::fs;
use std::path::PathBuf;
use serde::{Serialize, Deserialize};
#[derive(Serialize, Deserialize, Default)]
struct MojaStruktura {
data: Vec<String>,
}
impl MojaStruktura {
fn nacitaj_zo_suboru(cesta: &PathBuf) -> Option<MojaStruktura> {
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:
#[derive(Serialize, Deserialize, Default)]
struct Adresar {
kontakty: Vec<Kontakt>,
}
#[derive(Serialize, Deserialize, Clone)]
struct Kontakt {
meno: String,
telefon: String,
}
5b. Napíš program, ktorý:
- Vytvorí
Adresars 2 kontaktmi - Uloží ho do
"adresar.json" - Načíta ho späť
- 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
#[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
#[derive(Default)]
Kedy: Keď chceš vytvoriť inštanciu s defaultnými hodnotami.
#[derive(Default, Serialize, Deserialize)]
struct Kniznica {
knihy: Vec<Kniha>, // 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<T>→vec![]i32, u32, f64...→0bool→falseOption<T>→None
Clone
#[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
#[derive(Debug)]
Kedy: Keď chceš println!("{:?}", struktura). Užitočné pri debugovaní.
PartialEq
#[derive(PartialEq)]
Kedy: Keď chceš porovnávať == a != medzi inštanciami.
#[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
// 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<Kniha>,
}
Ú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<T> sa serializuje špeciálne:
#[derive(Serialize, Deserialize, Debug)]
struct Profil {
meno: String,
prezyvka: Option<String>,
vek: Option<u32>,
}
// 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:
// 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<String>,
#[serde(default)]
vek: Option<u32>,
}
// 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<String>, vek: u32 }. Serializuj študenta s emailom aj bez. Porovnaj JSON.
7b. Deserializuj tento JSON na štruktúru:
{"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
#[derive(Serialize, Deserialize)]
struct Trieda {
nazov: String,
studenti: Vec<String>,
}
let trieda = Trieda {
nazov: "4.A".into(),
studenti: vec!["Anna".into(), "Boris".into()],
};
// {
// "nazov": "4.A",
// "studenti": ["Anna", "Boris"]
// }
HashMap → JSON objekt
use std::collections::HashMap;
#[derive(Serialize, Deserialize)]
struct Slovnik {
preklady: HashMap<String, String>,
}
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
#[derive(Serialize, Deserialize)]
struct Adresa {
ulica: String,
mesto: String,
}
#[derive(Serialize, Deserialize)]
struct Osoba {
meno: String,
adresa: Adresa, // vnorený objekt
telefony: Vec<String>, // 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<String, Vec<String>> (kategória → slová). Serializuj s 2 kategóriami, každá s 3 slovami. Pozri JSON.
8b. Deserializuj tento JSON:
{
"meno": "Knižnica",
"knihy": [
{"nazov": "Duna", "rok": 1965},
{"nazov": "Hobbit", "rok": 1937}
]
}
Aké štruktúry potrebuješ?
8c. Máš HashMap<String, Vec<String>>. 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.
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<u64> = v["vek"].as_u64(); // Some(25)
let aktivna: Option<bool> = v["aktívna"].as_bool(); // Some(true)
Typy v Value:
enum Value {
Null,
Bool(bool),
Number(Number),
String(String),
Array(Vec<Value>),
Object(Map<String, Value>),
}
Vytváranie JSON dynamicky:
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
#[derive(Serialize, Deserialize)]
struct Osoba {
#[serde(rename = "full_name")]
meno: String,
vek: u32,
}
// {"full_name":"Anna","vek":25}
rename_all — premenuj všetky polia
#[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
#[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
#[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
#[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:
{"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:
// Serializácia — skoro nikdy nezlyhá (len ak typ nie je serializovateľný)
let vysledok: Result<String, serde_json::Error> = serde_json::to_string(&data);
// Deserializácia — zlyhá často (neplatný JSON, zlá štruktúra)
let vysledok: Result<MojTyp, serde_json::Error> = serde_json::from_str(json);
Vzory spracovania chýb
// 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<MojTyp, serde_json::Error> {
let data: MojTyp = serde_json::from_str(json)?;
Ok(data)
}
// 3. .ok() — zahoď chybu, vráť Option
let data: Option<MojTyp> = serde_json::from_str(json).ok();
// 4. .ok()? — v funkcii vracajúcej Option (TOTO JE VZOR ZO SKÚŠKY)
fn nacitaj(cesta: &PathBuf) -> Option<MojTyp> {
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::<MojTyp>(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<Kniha> — 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:
- Načítaj knižnicu zo súboru (ak neexistuje, vytvor prázdnu)
- Pridaj knihu
- Ulož späť
- Vráť true ak sa podarilo
Kapitola 12: Praktické vzory zo skúšky
Vzor 1: Kompletný skúškový vzor (lib.rs)
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<Kniha>,
}
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_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
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)
#[derive(Debug, 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 = 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:
{
"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<Odpoved>)
Štruktúra Milionar: otazky (Vec<Otazka>)
+ 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.