考虑一下:
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
}
Run Code Online (Sandbox Code Playgroud)
如果我不需要分配ok值data
,我会使用if let Err(err) = something()
,但是上面的代码是否有快捷方式,以避免复制粘贴Err/Ok分支,我认为,典型情况?像这样的东西if let
也会返回ok值.
sey*_*yed 25
Rust 1.65.0添加let-else
语句。所以你可以这样写:
loop {
let data = something()
let Ok(ok_data) = data else {
warn!("skipped.");
continue;
};
// ok_data is available here
let Ok(data2) = something_else(ok_data) else {
continue;
};
// and so on
}
Run Code Online (Sandbox Code Playgroud)
但您将无权访问该err
变量
如果您要经常"解包或继续"结果,请考虑将该逻辑封装在单独的函数中.有了它,您可以利用?
语法来引发函数之外的错误.然后可以将循环的流逻辑写在一个地方(尽管此时,您可能不再需要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(())
}
Run Code Online (Sandbox Code Playgroud)
虽然我认为E_net4的答案可能是最好的答案,但我还是为后代添加了一个宏,以防创建单独的函数并且?
由于某种原因而与运算符提早返回是不希望的。
这是一个简单的skip_fail!
宏,它continue
在传递错误时包含循环:
macro_rules! skip_fail {
($res:expr) => {
match $res {
Ok(val) => val,
Err(e) => {
warn!("An error: {}; skipped.", e);
continue;
}
}
};
}
Run Code Online (Sandbox Code Playgroud)
该宏可以用作 let ok_value = skip_fail!(do_something());
Playground链接使用skip_fail可以打印出被1、2和3整除的数字,并且当其中一个分区被截断时会打印错误。
再次,我相信?
在单独的函数中使用并返回“ Ok(end_result)
如果没有失败”可能是最惯用的解决方案,因此,如果可以使用该答案,则可能应该这样做。
如果必须将多个Ok
s 链接在一起,需要Ok
在下一个操作中使用 one的值,并且不关心错误出现在链中的哪个位置,请考虑and_then
:
loop {
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);
}
}
Run Code Online (Sandbox Code Playgroud)
where something
, something_else
,another_thing
和one_more
都返回某种形式的Result
. 尽管此示例删除了该continue
语句,and_then
但当Result
is 类型为时,通过短路有效地模拟它Err
。将跳过线路中的所有进一步呼叫。
您可以通过在只需要一个函数调用的语句上使用非闭包来使这更加简洁:
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);
}
}
Run Code Online (Sandbox Code Playgroud)
(注意函数上缺少括号,这表明它们被用作可调用对象而不是获取它们的返回值)