在 Rust 中如何处理 `match` 地狱?

在 Rust 中我们采用 Result<R, E> 的类型处理错误,这样(初学者)就特别容易出现错误处理嵌套地狱,比如如下一段利用 libgit2 读取一些 git repo 信息的代码:

    match Repository::open(first_arg) {
        Ok(repo) => {
//            println!("{:?}", repo);
            match repo.find_remote("origin") {
                Ok(mut origin) => {
                    println!("success!");
                    match repo.branches(Some(BranchType::Local)) {
                        Ok(branches) => {
                            for branch_result in branches {
                                match branch_result {
                                    Ok((branch, branch_type)) => {
                                        println!("Iterating at {:?}", branch.name());
                                        match branch.name() {
                                            Ok(Some(branch_name)) => {
                                                origin.fetch(&[branch_name], None, None);
                                            }
                                            _ => {
                                                println!("Error!")
                                            }
                                        }
                                    }
                                    Err(e) => {
                                        println!("{:?}", e)
                                    }
                                }
                            }
                        }
                        Err(e) => {
                            println!("{:?}", e)
                        }
                    }
                }
                Err(e) => {
                    println!("{:?}", e)
                }
            };

            match repo.remotes() {
                Ok(remotes) => {
                    for remote in remotes.iter() {
                        println!("{:?}", remote);
                    }
                }
                Err(e) => {
                    println!("{:?}", e);
                }
            };

            println!("hee");
        }
        Err(e) => panic!("failed to open: {}", e),
    };

每一层都进行 match,导致出现了极不可读的嵌套。

那么,正确的做法是什么呢?如上一段代码,优雅的写法是什么?


预览:

取消

具体解释见 std::ops::Try

use failure::Error;

fn some_fn() -> Result<(), Error> {
    let repo = Repository::open(first_arg)?;
    let mut origin = repo.find_remote("origin")?;
    let branches = repo.branches(Some(BranchType::Local))?;
    for branch_result in branches {
        let (branch, branch_type) = branch_result?;
        if let Some(branch_name) = branch.name()? {
            origin.fetch(&[branch_name], None, None);
        }        
    }
    let remotes = repo.remotes()?;
    for remote in remotes.iter() {
        println!("{:?}", remote);
    }
    Ok(())
}
修改于 12/18/2018, 4:13:55 AM

正确的做法是上知乎钓鱼

修改于 12/18/2018, 4:03:09 AM