CodeBlanks Logo Icon CodeBlanks

derive

Auto-implement with #[derive(Serialize, Deserialize)].

derive

#[derive(Serialize, Deserialize)] automatically generates code that walks field by field. For this to work, all field types must implement these traits too; the standard types (String, numbers, Vec, Option, HashMap) all do:

#[derive(Serialize, Deserialize)]
struct Raf {
    ad: String,
    kitaplar: Vec<Kitap>,      // Kitap must derive too
    etiketler: Vec<String>,
}

Enums can be derived too; variants are written as {"Ekle":{"metin":".."}} by default.

Composability through a trait

The power of derive is composability: each type only knows its own part, and nested structures just work. We can see the same idea with a small trait:

trait JsonYaz {
    fn json(&self) -> String;
}

impl JsonYaz for i32 {
    fn json(&self) -> String { self.to_string() }
}

impl<T: JsonYaz> JsonYaz for Vec<T> {
    fn json(&self) -> String {
        let ic: Vec<String> = self.iter().map(|x| x.json()).collect();
        format!("[{}]", ic.join(","))
    }
}

The Vec<T> implementation works without knowing how the inner type is written.

Practice Composable writer

Implement the JsonYaz trait for i32, &str (quoted) and Vec<T: JsonYaz>. Print the results for vec![1, 2, 3] and vec!["a", "b"] separated by a space.

Starter code

main.rs
fn main() {
    // buraya yaz
}

Sample solution

main.rs
trait JsonYaz {
    fn json(&self) -> String;
}

impl JsonYaz for i32 {
    fn json(&self) -> String {
        self.to_string()
    }
}

impl JsonYaz for &str {
    fn json(&self) -> String {
        format!("\"{}\"", self)
    }
}

impl<T: JsonYaz> JsonYaz for Vec<T> {
    fn json(&self) -> String {
        let ic: Vec<String> = self.iter().map(|x| x.json()).collect();
        format!("[{}]", ic.join(","))
    }
}

fn main() {
    println!("{} {}", vec![1, 2, 3].json(), vec!["a", "b"].json());
}

Expected output

[1,2,3] ["a","b"]

Questions and answers

Review the lesson questions together with their answers. To test yourself, solve the lesson interactively.

1 What happens if a field's type doesn't implement <code>Serialize</code>?

  • The derive gives a compile error Correct answer
  • The field is skipped
  • null is written
  • Runtime error

Explanation: The error tells which field is the problem. Either that type must derive too, or the field is left out with #[serde(skip)].

2 Blanket implementation

Question
impl<T: ____> JsonYaz for Vec<T> {
    fn json(&self) -> String { .. }
}
Answer
impl<T: JsonYaz> JsonYaz for Vec<T> {
    fn json(&self) -> String { .. }
}

Explanation: Vec<T> is JsonYaz as long as its elements are JsonYaz.

3 Value and JSON

Term Meaning
42 42
"a" "a"
vec![1, 2, 3] [1,2,3]
vec!["a", "b"] ["a","b"]

All lessons in Intermediate