How to return a string value from a nested struct with option fields

I am parsing JSON into structs using serde, and for one specific situation I am trying obtain a value or return "-", indicating no name (which are named 'Ni' or 'No' for None-inner and None-outer in the code below).

I am successful in doing so using the below nested match.

The question I have is if I can do this in a more compressed way possibly more idiomatic (such as serialising functions?

fn main() {

    #[derive(Debug)]
    struct InnerTest {
        c: Option<String>
    }

    #[derive(Debug)]
    struct Test {
        a: String,
        b: Option<InnerTest>,
    }

    let mut t: Vec<Test> = Vec::new();
    t.push( Test { a: "a".to_string(), b: None  });
    t.push( Test { a: "aa".to_string(), b: Some(InnerTest { c: None  }) });
    t.push( Test { a: "aa".to_string(), b: Some(InnerTest { c: Some("c".to_string())  }) });

    //println!("{:#?}", t);

    // option 1: open
    for tt in t {
        let o = match tt.b {
            Some(x) => {
                match x.c {
                    Some(i) => i.to_string(),
                    None => String::from("Ni")
                }
            },
            None => String::from("No"),
        };
        println!("{}", o);
    }
}

If you only want to get the string you can do this:

let o = tt.b.as_ref().map(|x| x.c.as_deref().unwrap_or("Ni")).unwrap_or("No");

as_ref() turns the option to Option<&InnerTest> and as_deref() turns x.c into Option<&str> so it would play more nicely with the literals.

It gives you &str in the end, unlike your original code which returned String, but you can change this by adding to_string or String::from at the end.

1 Like

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.