是否有展开或继续循环的快捷方式?
Is there a shortcut to unwrap or continue in a loop?
考虑一下:
loop {
let data = match something() {
Err(err) => {
warn!("An error: {}; skipped.", err);
continue;
},
Ok(x) => x
};
let data2 = match something_else() {
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
这样的东西也会 return 好的值。
如果您要经常 "unwrap or continue" 结果,请考虑将该逻辑封装在一个单独的函数中。有了它,您可以利用 ?
语法从函数中引发错误。然后可以将循环的流逻辑写在一个地方(尽管此时,您可能不再需要 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(())
}
如果必须把多个Ok
链接在一起,需要在下一次运算中使用一个Ok
的值,不用关心where 在链中出现错误,考虑 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);
}
}
其中 something
、something_else
、another_thing
和 one_more
都是 return Result
的某种形式。尽管此示例删除了 continue
语句,但当 Result
的类型为 Err
时,and_then
通过 short-circuiting 有效地模拟了它。所有后续呼叫都将被跳过。
您可以通过在只需要一个函数调用的语句上使用 non-closures 来使其更加简洁:
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);
}
}
(请注意函数上缺少括号,这表明它们被用作可调用对象而不是采用它们的 return 值)
虽然我认为 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());
同样,我相信在单独的函数中使用 ?
,如果没有失败则返回 Ok(end_result)
,这可能是最惯用的解决方案,所以如果你可以使用那个答案,你可能应该.
如果您愿意使用不稳定的功能,您可以为此使用 try 块:
#![feature(try_blocks)]
pub fn something() -> Result<String, String> {
Err(String::from("Badness"))
}
pub fn something_else() -> Result<String, String> {
Ok(String::from("Ok"))
}
pub fn main() {
loop {
let result: Result<(), String> = try {
let data = something()?;
let data2 = something_else()?;
};
if let Err(e) = result {
println!("An error: {}; skipped.", e)
}
}
}
正如 shepmaster 在评论中提到的那样,这可以在没有任何不稳定特性的情况下使用立即计算的闭包(立即调用函数表达式,简称 IIFE)来完成。这是MutantOctopus在该解决方案评论中提出的E_net4对解决方案的修改。
pub fn something() -> Result<String, String> {
Err(String::from("Badness"))
}
pub fn something_else() -> Result<String, String> {
Ok(String::from("Ok"))
}
pub fn main() {
loop {
let result: Result<(), String> = (|| {
let data = something()?;
let data2 = something_else()?;
Ok(())
})();
if let Err(e) = result {
println!("An error: {}; skipped.", e)
}
}
}
你可以使用我的 unwrap_or crate 来完成这个。
您可以使用它来编写漂亮干净的代码:
unwrap_or_ok!(callable(&mut param), _, return);
loop {
let data = unwrap_ok_or!(something(), err, {
warn!("An error: {}; skipped.", err);
continue;
});
let data2 = unwrap_ok_or!(somethingElse(), err, {
warn!("An error: {}; skipped.", err);
continue;
});
}
考虑一下:
loop {
let data = match something() {
Err(err) => {
warn!("An error: {}; skipped.", err);
continue;
},
Ok(x) => x
};
let data2 = match something_else() {
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
这样的东西也会 return 好的值。
如果您要经常 "unwrap or continue" 结果,请考虑将该逻辑封装在一个单独的函数中。有了它,您可以利用 ?
语法从函数中引发错误。然后可以将循环的流逻辑写在一个地方(尽管此时,您可能不再需要 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(())
}
如果必须把多个Ok
链接在一起,需要在下一次运算中使用一个Ok
的值,不用关心where 在链中出现错误,考虑 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);
}
}
其中 something
、something_else
、another_thing
和 one_more
都是 return Result
的某种形式。尽管此示例删除了 continue
语句,但当 Result
的类型为 Err
时,and_then
通过 short-circuiting 有效地模拟了它。所有后续呼叫都将被跳过。
您可以通过在只需要一个函数调用的语句上使用 non-closures 来使其更加简洁:
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);
}
}
(请注意函数上缺少括号,这表明它们被用作可调用对象而不是采用它们的 return 值)
虽然我认为 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());
同样,我相信在单独的函数中使用 ?
,如果没有失败则返回 Ok(end_result)
,这可能是最惯用的解决方案,所以如果你可以使用那个答案,你可能应该.
如果您愿意使用不稳定的功能,您可以为此使用 try 块:
#![feature(try_blocks)]
pub fn something() -> Result<String, String> {
Err(String::from("Badness"))
}
pub fn something_else() -> Result<String, String> {
Ok(String::from("Ok"))
}
pub fn main() {
loop {
let result: Result<(), String> = try {
let data = something()?;
let data2 = something_else()?;
};
if let Err(e) = result {
println!("An error: {}; skipped.", e)
}
}
}
正如 shepmaster 在评论中提到的那样,这可以在没有任何不稳定特性的情况下使用立即计算的闭包(立即调用函数表达式,简称 IIFE)来完成。这是MutantOctopus在该解决方案评论中提出的E_net4对解决方案的修改。
pub fn something() -> Result<String, String> {
Err(String::from("Badness"))
}
pub fn something_else() -> Result<String, String> {
Ok(String::from("Ok"))
}
pub fn main() {
loop {
let result: Result<(), String> = (|| {
let data = something()?;
let data2 = something_else()?;
Ok(())
})();
if let Err(e) = result {
println!("An error: {}; skipped.", e)
}
}
}
你可以使用我的 unwrap_or crate 来完成这个。
您可以使用它来编写漂亮干净的代码:
unwrap_or_ok!(callable(&mut param), _, return);
loop {
let data = unwrap_ok_or!(something(), err, {
warn!("An error: {}; skipped.", err);
continue;
});
let data2 = unwrap_ok_or!(somethingElse(), err, {
warn!("An error: {}; skipped.", err);
continue;
});
}