【问题标题】:What's the recommended way to produce side effects in control flow using Result?使用 Result 在控制流中产生副作用的推荐方法是什么?
【发布时间】:2019-04-07 15:53:51
【问题描述】:

Result::and_then() 非常适合编写控制流。

fn some_fn() -> Result<String, Error> {
    Ok("Yay".to_string())
}
some_fn()
    .and_then(|value| some_other_fn())
    .and_then(|some_other_value| /* ... */)

有时我们想要创建一个副作用并仍然传播发出的值。假设我们想在收到值的那一刻打印它:

some_fn()
    .and_then(|value| {
        println!("{}", &value);
        some_other_fn()
    })
    .and_then(|some_other_value| /* ... */)

有没有更好的方法来做到这一点?像Reactive Extensions' tap() operator 这样的东西会很棒。

【问题讨论】:

  • 我们想在收到值的那一刻打印出来——但你还是想打电话给some_other_function?如果是这样,你有什么问题?
  • 这正是我所指的。我所拥有的一切都没有问题。我只是睁大眼睛和耳朵以获得更优雅的解决方案(如果可能的话)。一如既往,您的回答非常有道理 - 谢谢!
  • 副作用永远不会优雅

标签: rust control-flow


【解决方案1】:

mapand_then 适用于您想要转换值的情况。使用matchif let 适合副作用:

let r = some_fn();

if let Ok(v) = &r {
    println!("{}", v);
}

r.and_then(|_| some_other_fn())

另见:

假设ResultOk 时,您只关心副作用...

您还可以创建一个扩展特征,将所需的方法添加到Result。我主张称它为inspect,因为这是the parallel method on Iterator 的名称。

trait InspectExt<T> {
    fn inspect<F>(self, f: F) -> Self
    where
        F: FnOnce(&T);
}

impl<T, E> InspectExt<T> for Result<T, E> {
    fn inspect<F>(self, f: F) -> Self
    where
        F: FnOnce(&T),
    {
        if let Ok(v) = &self {
            f(v)
        }
        self
    }
}
some_fn()
    .inspect(|v| println!("{}", v))
    .and_then(|_| some_fn())

另见:

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-05-08
    • 1970-01-01
    • 1970-01-01
    • 2020-05-03
    • 2014-08-18
    • 1970-01-01
    • 2019-09-15
    相关资源
    最近更新 更多