Chaining Option and Result with `?` operator

Viewed 607

Is there a way to chain a Result and an Option with ? so that the following code works? What would be the return type? I am happy to return some kind of an Error if the option is None.

struct Status {
   serial: Option<&'static str>;
}

fn serial(status_mutex: Mutex<Option<Status>>) -> Result<&'static str, ...> {
    status_mutex.lock()?.serial?
}
2 Answers

Use Option::ok_or or Option::ok_or_else:

fn serial(status_mutex: Mutex<Option<Status>>) -> Result<&'static str, ...> {
    status_mutex.lock()?.serial.ok_or(your_error_here)
}

Edit: as @user4815162342 commented, your_error returned by the serial fn and the one you would use in ok_or should implement From<PoisonError>.

Another approach would be to map the lock error:

fn serial(status_mutex: Mutex<Option<Status>>) -> Result<&'static str, your_error> {
    status_mutex.lock()
        .map_err(conver_to_my_error)?
        .serial
        .ok_or(your_error_here)
}

In the Rust book, section 3.3.1, this specific use case is mentioned. In short, using the ? operator like the question is suggesting isn't currently allowed in Rust, but here's the relevant paragraph from the section:

One current restriction is that you cannot use ? for both in the same function, as the return type needs to match the type you use ? on. In the future, this restriction will be lifted.

Edit:

On the nightly version of Rust, you could implement a custom Error that implements From<NoneError>. This would allow for using the ? operator to unwrap a value of type Option<T>. If that unwrap returns a None variant, then an error can be returned. Check the documentation here.

Related