rust

How to pass a closure to be executed before the Ok variant returns value


I have a function that returns a Result type. Inside this function another function is being called which returns Result type. And, if the returned value is an Err variant, call a function/closure before bubbling up that error, else if it's Ok variant call a function/closure and then simply return the contained value. This is what I've written so far

fn foo1() -> Result<i32, String> {
    Err("error".to_string())
}

fn foo2() -> Result<String, bool> {
    let res = foo1().map_err(|err| {
        println!("foo1 failed {}", err);
        false
    })?;

    // I know I can call some closure in here, but I want something like map_err which will call different closures depending on the Result variant
    Ok(res.to_string())
}

fn main() {
    foo2();
}

Solution

  • I would say you're probably at a point where your needs are sufficiently specialised that you should just drop down to a match and implement the actual thing you need.

    Combinators and higher order functions are there to signpost ways and provide semantic information to the reader, but if they don't apply straightforwardly or don't make things clearer it's perfectly fine and expected to not use them.

    So we can desugar your snippet to this:

    fn foo1() -> Result<i32, String> {
        Err("error".to_string())
    }
    
    fn foo2() -> Result<String, bool> {
        match foo1() {
            Ok(res) => {
                println!("foo1 succeeded {}", res);
                Ok(res.to_string())
            }
            Err(err) => {
                println!("foo1 failed {}", err);
                Err(false)
            }
        }
    }
    
    fn main() {
        let res = foo2();
        match res {
            Ok(_) => println!("succeeded"),
            Err(_) => println!("failed")
        }
    }
    

    and I don't think we're worse off for it. Quite the opposite in fact: the use of a raw match actually signals to the reader (including future-you) that we're performing a non-obvious set of transformations.