How to simplify nested match when Result is not returned in the end

struct A(pub String);
struct B(pub String);
struct C(pub String);

impl From<B> for A {
    fn from(v:B) -> Self{
        Self(v.0)
    }
}

impl From<C> for A {
    fn from(v:C) -> Self{
        Self(v.0)
    }
}

fn get_result() -> Result<C, B>{
    Ok(C("c".to_string()))
}

fn do_something(c:C) -> Result<String, C>{
    // do something
    if &c.0 == "success"{
        return Ok(c.0);
    }
    Err(c)
}

fn test() -> A {
    let b = get_result();
    match b {
        Ok(c) => {
            match do_something(c) {
                Ok(s) => A(s),
                Err(c) => c.into()
            }
        },
        Err(b) => b.into()
    }
    // How to simplify it to something like this
    // let c = b?;
    // let s = do_something(c)?;
    // A(s)

}

A more pertinent example

I don't really understand what purpose the inner Err(c) serves, if it's always Err? What are you trying to do in the real use case?

I guess with your inner match, you mean something like

fn test_2(c: C) -> Result<String, C> {
    Err(c)
}
// ...
        Ok(c) => {
            match test_2(c) {
                Ok(s) => A(s),
                Err(c) => c.into()
            }
        },

Then you could have something like

    // Start with Result<C, B> and map the C to...
    b.map(|c| test_2(c).map(|s| A(s)).unwrap_or_else(Into::into))
//            ^^^^^^^^^ ^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^
//    Result<String, C> Result<A, C>  A
//
//  We now have a Result<A, B>, unwrap or turn the B into an A
        .unwrap_or_else(Into::into)

Playground.

N.b. in case you haven't seen it, unwrap_or_else(Into::into) is the same as unwrap_or_else(|e| e.into()).

sorry,this is meaningless.I modified the use case.

    // Result<Result<String, C>, B> -> A
    b.map(|rsc| rsc.map(A).unwrap_or_else(Into::into))
        .unwrap_or_else(Into::into)

...for your modified use case as of just before now (Discourse "helpfully" removed my quote)

thanks, but I wonder if there is a solution like ? or try!.

I don't really recommend it, but

fn _test(b: Result<Result<String, C>, B>) -> Result<A, A> {
    Ok(A(b??))
}

fn test() -> A {
    let b:Result<Result<String, C>, B> = Ok(Err(C("c".to_string())));
    _test(b).unwrap_or_else(|a| a)
}

Or perhaps

enum NeverType {}
fn _test(b: Result<Result<String, C>, B>) -> Result<NeverType, A> {
    Err(A(b??))
}

fn test() -> A {
    let b:Result<Result<String, C>, B> = Ok(Err(C("c".to_string())));
    match _test(b) {
        Ok(_) => unreachable!(),
        Err(a) => a
    }
}

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.