Search code examples
rustrust-result

Is there a simple way to get Result<&T, E> from Result<T, E>?


Result<T, E>.as_ref() will convert it to Result<&T, &E>, but the expected result is Result<&T, E>.


Solution

  • If you want to place conversion in a function, the function will have to take the Result by reference. This is because, in order to use &T in the result type, there must be a reference in at least one of the arguments (so that the returned reference can have a lifetime). This will pose the problem in the Err case in which you'd ideally want to consume the original Result, but aren't allowed to do so because you get it by reference. If you can get away with requiring E: Clone, then this will work:

    pub fn convert_and_return<T, E: Clone>(r: &Result<T, E>) -> Result<&T, E> {
        match r {
            Ok(t) => Ok(t),
            Err(e) => Err(e.clone()),
        }
    }
    

    Another possibility is to require E to implement Default, in which case you could extract the Err(e) from the original Result and leave the default in its place:

    pub fn convert_and_return<T, E: Default>(r: &mut Result<T, E>) -> Result<&T, E> {
        match r {
            Ok(t) => Ok(t),
            Err(e) => Err(std::mem::take(e)),
        }
    }
    

    If you don't need to extract conversion in a function, but just want to transform the Result in-place, then you don't need to require any traits of E. You can either consume the result or not depending on a condition, and borrow checker will allow it. The code is then as simple as:

    pub fn convert_and_use<T, E>(r: Result<T, E>) {
        let _r: Result<&T, E> = match r {
            Ok(ref v) => Ok(v),
            Err(e) => Err(e),
        };
        // use it here...
    }