Serde getting back deserialized values

Hello

I have code:

use serde::{Deserialize };

#[derive(Deserialize, Debug)]
struct Data {
    key_a: String,
    key_b: Vec<String>,
    key_c: KeyC,
}

#[derive(Deserialize, Debug)]
struct Info {
    key_d: String,
}

#[derive(Deserialize, Debug)]
#[serde(untagged)]
enum KeyC {
    VerA(String),
    VerB(Vec<Info>),
}


fn typed_example() {

    let data = r#"[
            {"key_a":"valueAB","key_b":["AR","valueYH","valueKI"],"key_c":[{"key_d":"valueED"}]},
            {"key_a":"valueQS","key_b":["ER","valueIK","valueDF"],"key_c":[]},
            {"key_a":"valueQS","key_b":["ER","valueIK","valueDF"],"key_c":""},
            {"key_a":"valueAB","key_b":["AR","valueCT","valueHP"],"key_c":[{"key_d":"valueUF"}]}
        ]"#;

    let p: Vec<Data> = serde_json::from_str(data).unwrap();

    for item in p.iter() {

        println!("from json: {} == {:?}",item.key_a, item.key_c );
    }
}


fn main() {

    let _ww = typed_example();

}

If I run it I got:

from json: valueAB == VerB([Info { key_d: "valueED" }])
from json: valueQS == VerB([])
from json: valueQS == VerA("")
from json: valueAB == VerB([Info { key_d: "valueUF" }])

As you can see "item.key_a" deserialized in value, but "key_c" is not
So my question is how to get "key_d" out of "key_c"?

Thank you in advance

1 Like

Would you mind elaborating on what you mean by this? I don't see how key_c is not deserialized as a value.

You can use pattern matching for this. For example:

        match &item.key_c {
            KeyC::VerB(v) => {
                for Info { key_d } in v {
                    println!("key_d: {key_d}");
                }
            }
            _ => {}
        }

Playground.

1 Like

In my code "key_c" is an array: [{"key_d":"valueED"}].
Can I get value from it like key_c[0].key_d? No

And I completely agree that I am just learning Rust because I need executable for Linux.
But value for my understanding it is not KeyC::VerB([Info { key_d: "valueED" }]), it is "valueED".

I know that I can push deserialized data into serde_json::Value, but it won't work with Enum (or may be I misunderstood docs).

Thank you very much for your suggestion.
I may add if let in it, but I got the idea.

The key to understand the printed out representation is that in Rust you have two traits for displaying values:

  • Display is used to print values in human-readable form
  • Debug is used to print values for debugging purposes, which means that you'll (Depending on how you implemented the trait of course) see the memory representation of the model most of the time (i.e. when you derived the implementation).

Now, when you printed out the values, you used the Display trait for the first value, and the Debug trait for the second (notice the :? notation which tells the formatter to use the Debug representation).

println!("from json: {} == {:?}",item.key_a, item.key_c );
1 Like

To get everyone on the same terminology, since there seems to be some confusion here:

A "value" has an ideal, logical value that is what is meant, and several possible "representations" that uniquely construct, identify or describe (depending on your interpretation) that logical value.

An important representation is the in memory representation, for example in Rust a string is represented by a span of memory that encodes the characters in sequence (specifically, in UTF-8), and the span is represented by the location of the start of the characters and the length:

       +---------+---+  +---+---+---+---+---+
key_a: | .data   | *-+--+ k | e | y | _ | a |
       +---------+---+  +---+---+---+---+---+
       | .length | 5 |
       +---------+---+

When we talk about a value in programming, we are often actually talking about this in-memory representation of the value.

"Serialized" is a term meaning that the in memory structure of a value has been flattened into a single string or flat byte array such that it can be written to a file, over the network etc.. There are several ways to serialize values, which are commonly known as formats.

"Quoted" is a term meaning a representation of a value that has some quote character (commonly ") placed around it and a set of "special" characters "escaped" in some alternative form, (commonly a \ before another character), with the intention that the exact underlying value is easily readable without ambiguities in an unknown context.

In Rust, when using Display, eg via {}, string values are represented directly in the output.

When using Debug, eg via {:?}, string values are represented using (a subset of) Rust's quoting rules.

Separately, JSON is a serialization format that uses JS syntax (it stands for "JavaScript Object Notation") - here strings are represented using (a subset of) JS's string quoting rules. These are very close to Rust's, as both are based on the quoting of the C language.


So, putting it all together, what you're seeing is that the deserialized values are being quoted in the Debug view, which makes it look a little like the string has not been deserialized, though it has (otherwise, since you're quoting the value, you would see quotes around escaped quotes like "\"this\"")

So what you're asking is actually just "how do I get values out of enums", it's not anything to do with serialization any more. The answer is match, as described earlier in the thread, or the shorthand if let

Let me know if there's anything confusing in this; there's a lot of technical terms.

3 Likes

@jofas, @firebits.io, @simonbuchan
Thank you for your answers.
I think I am good.