是否存在用于展开或继续循环的快捷方式?

问题描述 投票:2回答:4

考虑此:

loop {
    let data = match something() {
        Err(err) => {
            warn!("An error: {}; skipped.", err);
            continue;
        },
        Ok(x) => x
    };

    let data2 = match somethingElse() {
        Err(err) => {
            warn!("An error: {}; skipped.", err);
            continue;
        },
        Ok(x) => x
    };

    // and so on
}

如果不需要将ok值分配给data,则可以使用if let Err(err) = something(),但是上面代码的快捷方式是避免在此代码上粘贴粘贴Err / Ok分支,我认为典型的情况是?类似if let的东西也将返回ok值。

loops rust pattern-matching control-flow
4个回答
8
投票

虽然我认为E_net4的答案可能是最好的答案,但我为后代添加了一个宏,以防创建一个单独的函数,并且由于某些原因使用?运算符提早返回是不希望的。

这里是一个简单的skip_fail!宏,当传递错误时continue是一个包含循环:

macro_rules! skip_fail {
    ($res:expr) => {
        match $res {
            Ok(val) => val,
            Err(e) => {
                warn!("An error: {}; skipped.", e);
                continue;
            }
        }
    };
}

此宏可以用作let ok_value = skip_fail!(do_something());

Playground link which uses skip_fail to print out numbers divisible by 1, 2, and 3, and print an error when one of the divisions would truncate.

再次,我相信在单独的函数中使用?,如果没有失败,则返回Ok(end_result)可能是最惯用的解决方案,因此,如果可以使用该答案,则应该这样做。


9
投票

如果经常要对结果“展开或继续”,请考虑将该逻辑封装在单独的函数中。有了它,您就可以利用?语法从函数中引发错误。然后可以在单个位置编写循环的流程逻辑(尽管此时,您可能不再需要continue)。

loop {
    if let Err(err) = do_event() {
        warn!("An error: {}; skipped.", err);
        // continue; // you also don't need this
    }
}

fn do_event() -> Result<(), YourErrorType> {
    let data = do_something()?; // 
    let x = something_more()?;  // error propagation!
    Ok(())
}

5
投票

如果必须将多个Ok链接在一起,则需要在下一个操作中使用一个Ok的值,并且不关心链中出现错误的where,请考虑[C0 ]:

and_then

and_thenloop { let outcome = something() .and_then(|a| something_else(a)) .and_then(|a| another_thing(a)) .and_then(|a| { let b = a + salt; one_more(b) }); if let Err(e) = outcome { warn!("An error: {}; skipped.", e); } } somethingsomething_else全部返回某种形式的another_thing。即使此示例删除了one_more语句,当Result的类型为continue时,and_then也会通过短路有效地模拟它。该线路上的所有其他呼叫将被跳过。

您可以通过仅要求一个函数调用的语句使用非闭包来使之更加简洁:

Result

((请注意函数上没有括号,这表明它们被用作可调用对象,而不是获取其返回值)


1
投票

如果您愿意使用不稳定的功能,则可以为此使用try块:

Err

正如shepmaster在评论中提到的那样,可以使用立即评估的闭包(即立即调用的函数表达式,简称IIFE),而无需任何不稳定的特征来完成此操作。这是MutantOctopus在解决方案注释中提出的E_net4解决方案的修改。

loop {
    let outcome = something()
                  .and_then(something_else)
                  .and_then(another_thing)
                  .and_then(|a| one_more(a + salt));
    if let Err(e) = outcome {
        warn!("An error: {}; skipped.", e);
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.