我发现自己经常做类似以下的事情:
fn foo() -> Result<i32, String> {
let cur = match something_that_returns_an_option() {
Some(cur) => cur,
None => return Err("Some error"),
};
// use `cur`
1
}
Run Code Online (Sandbox Code Playgroud)
如果我需要多个变量,我会一遍又一遍地保留此模式,或者如果让/匹配则嵌套。
是否有一种更符合人体工程学的方法来处理从选项中重复提取值?
Aid*_*en4 11
您正在寻找Option::ok_or. 它允许您将 an 映射Option到Result具有提供的错误的 a 。与?操作员结合使用,你可以很好地清理事情:
fn foo() -> Result<i32, String> {
let cur = something_that_returns_an_option().ok_or("some error")?;
Ok(cur + 1)
}
Run Code Online (Sandbox Code Playgroud)
Option::ok_or_else也可能有帮助,因为它会惰性地评估错误分支。
在您的示例中,您不仅希望继续、中断或返回常规值,还希望返回错误。对于这种特殊情况,Aiden4 的答案就是正确的选择。或者,如果您无论如何都在使用,您应该看到这个。
但我曾经遇到过这样的情况:我想None直接解开 或 (在 的情况下)continue或非错误值。breakreturn
let -else功能在 Rust 1.65 中得到了稳定。以下是如何使用它的示例:
let options = vec![Some(74), None, Some(9)];
for o in options {
let Some(v) = o else { continue };
println!("v = {v}");
}
Run Code Online (Sandbox Code Playgroud)
Rust(仍然)没有提供一种简短的方法来做到这一点。
这是一个“one-liner”,可以解决问题,但仍然有点冗长:
let v = if let Some(d) = some_option_value { d } else { continue; };
Run Code Online (Sandbox Code Playgroud)
如果您想要更短的解决方案,请考虑以下事项......
你可以写一个这样的宏:
macro_rules! unwrap_or {
($e:expr, $or_do_what:expr) => {
if let Some(d) = $e { d } else { $or_do_what }
};
}
Run Code Online (Sandbox Code Playgroud)
这将允许您编写如下代码:
let options = vec![Some(74), None, Some(9)];
for o in options {
let v = unwrap_or!(o, continue);
// ...
}
Run Code Online (Sandbox Code Playgroud)
这是一个微不足道的例子,但我认为如果您需要执行多次检查,那么最大的好处就会到来,这样就不用编写这样的“惯用”内容:
for thing in things {
if let Some(a) = thing {
// ...
if let Some(b) = a.another_opt {
// ...
if let Some(c) = a.yet_another_opt {
// ...
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
,您可以通过避免嵌套多个块来简化代码,如下所示:
for thing in things {
let a = unwrap_or!(thing, continue);
// ...
let b = unwrap_or!(a.another_opt, continue);
// ...
let c = unwrap_or!(a.yet_another_opt, continue);
// ...
}
Run Code Online (Sandbox Code Playgroud)
当然,这是否是一个好的做法是主观的。