How to get Result aligned with Result?

前端 未结 1 1682
别那么骄傲
别那么骄傲 2021-01-19 22:35

I have this code

fn get_last_commit () -> String {

    Command::new(\"git\")
            .arg(\"rev-parse\")
            .arg(\"HEAD\")
            .outp         


        
相关标签:
1条回答
  • 2021-01-19 23:08

    The problem is that the closure passed to the and_then needs to return a Result with the same error type as the Result that and_then was called on; otherwise, there's no single type that and_then could return; and_then maps one Ok type to another, but keeps the error type the same.

    Since you are just throwing away the error value by converting it to an option with ok() that you unwrap anyhow, you can do that before calling and_then, and within the closure, as the Option type returned by and_then on an Option only depends on the value returned by the closure:

    fn get_last_commit () -> String {
    
        Command::new("git")
                .arg("rev-parse")
                .arg("HEAD")
                .output()
                .ok()
                .and_then(|output| {
                    String::from_utf8(output.stdout).ok()
                })
                .expect("error invoking git rev-parse")
    }
    

    If you actually cared about the error value, you would need to define your own error type that could contain either of the two types of errors, and wrap either of the errors up. The FromError trait and try! macro offer a convenient way to is wrap up the value and return it from one of several places in your function, though in this case map_err would probably be a better way to do that as you are doing it all via chained method calls rather than separate statements.

    enum MyError {
        Io(IoError),
        Utf8(FromUtf8Error)
    }
    
    fn get_last_commit () -> Result<String,MyError> {
    
        Command::new("git")
                .arg("rev-parse")
                .arg("HEAD")
                .output()
                .map_err(MyError::Io)
                .and_then(|output| {
                    String::from_utf8(output.stdout)
                           .map_err(MyError::Utf8)
                })
    }
    

    If you notice, this parallels the earlier solution fairly closely, coercing both of the result types into a single common type; in the first solution, it just throws away the error value by using ok(), while in the second, it preserves the error value so you can return it, but you now need the extra machinery of a type that could wrap either.

    0 讨论(0)
提交回复
热议问题