Rewriting a simple match involving refs & borrowing using Option methods

Consider the below code, where I have a struct that contains an Option<String> and has a method for returning either the value within the option or a default value, both as &str. I've implemented this using a match statement, but I feel that it must be possible to rewrite this into a single line using Option methods. Unfortunately, all my attempts so far — the most complicated of which has been (&self.sopt).as_ref().unwrap_or_else(|| "<unknown>".into()) — fail to compile, usually because the &String is not being implicitly converted to a &str.

How can I rewrite this with Option methods? Please explain your answer.

(Playground)

struct Structure {
    sopt: Option<String>,
}

impl Structure {
    fn get_str(&self) -> &str {
        match &self.sopt {
            Some(s) => s,
            None => "<unknown>",
        }
    }
}

fn main() {
    let st = Structure { sopt: Some(String::from("foo")) };
    println!("{}", st.get_str());
}
self.sopt.as_deref().unwrap_or("unknown")

The .as_deref() combines changing String to &String (so that unwrap won't consume the value) and conversion from &String to &str.

2 Likes

That works for most of the code I'm trying to rewrite. I hope you don't mind this follow-up, but I'd also like to know how to simplify the same operation on the result of a Vec::get(), like so:

struct Structure {
    vs: Vec<String>,
}

impl Structure {
    fn get_head(&self) -> &str {
        self.vs.get(0).unwrap_or("<unknown>")
    }
}

fn main() {
    let st = Structure { vs: vec![] };
    println!("{}", st.get_head());
}

(Playground)

Here, Vec::get() returns an Option<&String>, and using as_deref() doesn't seem to change the type.

That's because in this case you already have an Option<&String> to begin with (Vec::get() returns Option<&T>), and the Deref impl for references is the identity function. So just map the deref call explicitly over the option:

self.vs.get(0).map(Deref::deref).unwrap_or("<unknown>")

This can, incidentally, be shortened further to

self.vs.get(0).map_or("<unknown>", Deref::deref)
3 Likes