Deriving Serialize and Deserialize¶
Level: 201 · working knowledge
One line: serde ↗ splits the job in two — the derive teaches your type how to describe itself, and a separate crate like serde_json decides what the bytes look like.
Stub — an outline, not a lesson. There is no runnable example behind this page yet, so nothing on it has been through the check that backs every other claim in this library. The bullets below are the questions the finished page has to answer.
What it has to cover¶
- The two-crate shape, and why it is not gratuitous: one derive gets you JSON, YAML, TOML, MessagePack and CBOR without touching the struct again
- What
#[derive(Serialize, Deserialize)]generates, at a level a reader can picture — a visitor walking your fields, not a reflection API, because Rust has none at runtime - The Cargo detail that stops everyone once:
serdeneedsfeatures = ["derive"], and the error when it is missing names the macro rather than the feature - The attributes worth knowing early —
#[serde(rename = "…")],rename_all,default,skip_serializing_if— for the day the JSON was designed by somebody else - An
enumover the wire: what the default tagging looks like, and why it is the first thing people override
The trap it exists for¶
Deriving both traits makes a struct part of a file format. Rename a field and yesterday's saved file no longer loads; add a field and it loads with an error unless something supplied a default. The struct stopped being an implementation detail at the moment of the derive, and nothing in the code says so.
See also¶
- The round trip — the test that catches exactly the breakage above
- The
Defaulttrait — what#[serde(default)]reaches for when a field is missing - Debug and Display — three ways to turn a value into text, and the audience each one has
Po polsku¶
W Javie czy Pythonie serializacja opiera się na refleksji: biblioteka w czasie działania programu ogląda pola obiektu i sama wie, co zapisać. W Ruscie refleksji nie ma, więc #[derive(Serialize, Deserialize)] niczego nie „ogląda” — to makro proceduralne, które w czasie kompilacji dopisuje do twojego typu kod przechodzący pole po polu. Stąd bierze się podział na dwa crate'y, który na początku wygląda na komplikację, a jest zaletą: serde uczy twój typ opisywać samego siebie, a dopiero serde_json (albo toml, serde_yaml, rmp-serde) decyduje, jak wyglądają bajty — jeden derive, wszystkie formaty; w Cargo.toml trzeba tylko pamiętać o features = ["derive"], bo bez tej flagi kompilator narzeka na brakujące makro, a nie na brakującą flagę. Pułapka, o której ta strona jest naprawdę: od chwili wpisania tego derive twoja struktura jest formatem pliku — zmiana nazwy pola to zmiana formatu i wczorajszy zapis przestaje się wczytywać, a w kodzie nie ma ani jednej linijki, która by o tym uprzedzała.
Szukaj po polsku: serializacja serde · makro proceduralne · brak refleksji w Ruscie · rust serde derive feature · cannot find derive macro Serialize