How can I pull data out of an Option for independent use?

Viewed 9786

Is there a way to 'pull' data out of an Option? I have an API call that returns Some(HashMap). I want to use the HashMap as if it weren't inside Some and play with the data.

Based on what I've read, it looks like Some(...) is only good for match comparisons and some built-in functions.

Simple API call pulled from crate docs:

use std::collections::HashMap;

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let resp = reqwest::blocking::get("https://httpbin.org/ip")?
        .json::<HashMap<String, String>>()?;
    println!("{:#?}", resp.get("origin"));
    Ok(())
}

Result:

Some("75.69.138.107")
3 Answers
if let Some(origin) = resp.get("origin") {
    // use origin
}

If you can guarantee that it's impossible for the value to be None, then you can use:

let origin = resp.get("origin").unwrap();

Or:

let origin = resp.get("origin").expect("This shouldn't be possible!");

And, since your function returns a Result:

let origin = resp.get("origin").ok_or("This shouldn't be possible!")?;

Or with a custom error type:

let origin = resp.get("origin").ok_or(MyError::DoesntExist)?;

Your options are a plenty.

if let Some(origin) = resp.get("origin") {
    // do stuff using origin
}
origin = resp.get("origin").unwrap()
// will panic if None
resp.get("origin").map(|origin| {
    // do stuff using inner value, returning another option
})
resp.get("origin").and_then(|origin| {
    // same as map but short-circuits if there is no inner value
})

The most common way is with if let:

if let Some(origin) = resp.get("origin") {
    origin.do_stuff()
}

For more fine grained control, you can use pattern matching:

match resp.get("origin") {
    Some(origin) => origin.do_stuff(),
    None => panic!("origin not found!")
}

You could also use unwrap, which will give you the underlying value of the option, or panic if it is None:

let origin = resp.get("origin").unwrap();

You can customize the panic message with expect:

let origin = resp.get("origin").expect("Oops!");

Or compute a default value with unwrap_or:

let origin = resp.get("origin").unwrap_or(&String::from("192.168.0.1"));

You can also return an error instead of panicking:

let origin = resp.get("origin").ok_or(Error::UnknownOrigin)?;
Related