使用组合器简化 Rust 匹配

Simplifying Rust matching with combinators

我有这样的东西:

match fnX(
    fnY(x), // Returns Result<(), X>
) // Returns Result<(), Y>
.await
{
    Ok(v) => {
        if v.is_err() {
            error!("error = {}", v);
        }
    }
    Err(e) => error!("error = {}", e),
};

我怎样才能用组合器写这个,这样我只需要 error! 一次?我不想对 Ok 值做任何事情,只是打印错误是来自 fnX 还是 fnY.

你不需要这样的"combinator"。

fnX 接受类型为 Result<(), X> 和 returns 的参数 Result<(), Y>

当代码比较复杂时,将表达式分开可能有助于提高可读性。

let result = fnY(x);
match fnX(result).await {
    Ok(v) => {
        // here v is ok value, in this case ()
    }
    Err(e) => error!("error = {}", e),
};

我假设你想简化这样的事情(删除与问题无关的 .await):

match fnX(x) { // Returns Result<X, EX>
    Ok(y) => match fnY(y) { // Returns Result<Y, EY>
        Ok(_) => println!("Success!"),
        Err(e) => error!("error = {}", e),
    },
    Err(e) => error!("error = {}", e),
}

如果错误类型相同,可以将代码简化为and_then:

match fnX(x).and_then(fnY) {
    Ok(_) => println!("Success!"),
    Err(e) => error!("error = {}", e),
}

如果错误类型不同,您可以使用map_err将它们转换为单一类型:

match fnX(x)
    .map_err(MyError::from)
    .and_then(|y| fnY(y).map_err(MyError::from))
{
    Ok(_) => println!("Success!"),
    Err(e) => error!("error = {}", e),
}

后者可以使用 map_for crate 的最新开发版本进行简化:

match map_for!(y <- fnX (x);
               v <- fnY (y);
               => v)
{
    Ok(_) => println!("Success"),
    Err(e @ MyError { .. }) => error!("error = {}", e),
}
  • 请注意,仅当编译器无法自动推断错误类型时才需要 @ MyError {..} 注释。
  • 完全免责声明:我是 map_for 箱子的作者。