Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to convert a Option<Result<T, Error>> to an Option<T> without unwrapping it?

Tags:

rust

I am trying to find a good way to convert an Option<String> to an Option<i8>.

For example,

use std::str::FromStr;

fn main() {
    let some_option: Option<String> = Some("too".to_owned()); 
    let new_option: Option<i8> = some_option.map(|x| i8::from_str(x.as_str())); 
}

I thought I could use the turbo fish to explicitly cast the type so something like this:

use std::str::FromStr;

fn main() {
    let some_option: Option<String> = Some("too".to_owned()); 
    let new_option: Option<i8> = some_option.map::<Option<i8>>(|x| i8::from_str(x.as_str())); 
}

However, the compiler points out this isn't the correct amount of parameters, so I thought this might work, but it doesn't:

use std::str::FromStr;

fn main() {
    let some_option: Option<String> = Some("too".to_owned()); 
    let new_option: Option<i8> = some_option.map::<Option<i8>,i8::from_str>(); 
}
like image 369
asteriskTheServer Avatar asked Dec 06 '22 15:12

asteriskTheServer


2 Answers

You can use the ok() and unwrap_or() functions:

fn test() -> Option<Result<u32, ()>> {
    Some(Ok(1))
}

fn main() {
    let x: Option<Result<_, _>> = test();
    println!("{:?}", x.map(|r| r.ok()).unwrap_or(None));
}
like image 134
Wesley Wiser Avatar answered Jan 13 '23 01:01

Wesley Wiser


Instead of creating an Option<Result<T, E>> in the first place, you can combine:

  1. Option::and_then, which applies a closure that returns an Option and flattens the result.

  2. Result::ok, which converts a Result to an Option, discarding the error.

fn main() {
    let some_option = Some("too".to_owned()); 
    let new_option = some_option.and_then(|x| x.parse::<u8>().ok()); 
}

You can use the same two tools to answer your direct question:

fn convert<T, E>(a: Option<Result<T, E>>) -> Option<T> {
    a.and_then(Result::ok)
}
like image 31
Shepmaster Avatar answered Jan 12 '23 23:01

Shepmaster