How to get rid of an Option when deserializing with serde?

Hi all,

I can't solve my problem.

I'm deserializing a YAML file to a struct. One of the YAML field is optional, and is usually mapped with an Option<T>. Example:

struct YamlFile {
      name: Option<String>,
}

But how to get rid of the Option so that if the field is found in YAML, it is deserialized, and if not, a default method is called ? That way, the struct will boil down to:

struct YamlFile {
      name: String,
}

I played with serde attributes but I didn't succeed. What I achieved is to keep the Option and call a default method to return Some(value).

I simplified here, but the field is not an Option<String> but an Option<Large struct>.

Thanks a lot for your hints.

See this thread:

@mbrubeck Thanks for your anwser. I did see your answer in the link you'be been providing. But I don't want a default, rather call another method. The only thing is just replace the T::default by another call ?

#[derive(Deserialize)]
struct YamlFile {
    #[serde(default)]
    name: String,
}

https://serde.rs/field-attrs.html#default

@Hyeonu Thanks, but this not what I want.

Let my elaborate. The following works well:

#[derive(Deserialize, Debug)]
struct Person {
    name: String,
    attributes: Option<Attributes>,
}


#[derive(Deserialize, Debug)]
struct Attributes {
    height: u8,
    weight: u8,
    left_handed: bool,
    title: String,
}

fn main() {
    let yaml = r#"
name: "john doe"
attributes:
    height: 6
    weight: 176
    left_handed: true
    title: "Lord"    
"#;

    let foo: Person = serde_yaml::from_str(yaml).unwrap();
    println!("foo={:?}", foo);
}

But what I want is:

#[derive(Deserialize, Debug)]
struct Person {
    name: String,
    attributes: Attributes,
}

and the same behavior if the attributes tag is found in YAML, or some defaults (by not Attributes::default()) for the Attributes struct if not.

For example:

Attributes { height: 5, weight: 150, left_handed: true, title: "General".to_string() }

Actually, this works:

fn attr_default() -> Attributes {
    Attributes { height: 5, weight: 150, left_handed: true, title: "General".to_string() }
}

#[derive(Deserialize, Debug)]
struct Person {
    name: String,
    #[serde(default = "attr_default")]
    attributes: Attributes,
}

Didn't expect to be so simple :wink:

2 Likes