Ok(value) 模式在 for 循环中如何工作?
What how does the Ok(value) pattern work in for loops?
我不明白以下模式的工作原理:
for Ok(value) in do_thing_get_results(){
use_thing(value)
}
循环会忽略 Err
结果吗?它会简单地 .unwrap()
他们并恐慌吗?它是否有另一个用于处理 Err
值的子句,以避免我编写 match
?
适当的 MCVE 给出:
fn the_answer() -> Result<u32, ()> {
Ok(42)
}
fn main() {
for Ok(foo) in Some(the_answer()) {
println!("{}", foo);
}
}
error[E0005]: refutable pattern in `for` loop binding: `Err(_)` not covered
--> src/main.rs:6:9
|
6 | for Ok(foo) in Some(the_answer()) {
| ^^^^^^^ pattern `Err(_)` not covered
|
= note: the matched value is of type `Result<u32, ()>`
Patterns used to bind names must be irrefutable, that is, they must guarantee that a name will be extracted in all cases.
If you encounter this error you probably need to use a match or if let to deal with the possibility of failure
您的代码根本无法编译。 Rust 不允许您在 for
循环绑定中使用 refutable patterns。
如果需要,您可以通过多种方式查看 Ok
变体。一种是在 循环中使用 if let
语句 。示例:
let res_values = vec![
Ok(11),
Ok(22),
Err(MyError::new("Foo")),
Ok(33),
];
for r in res_values {
if let Ok(v) = r {
println!("An Ok value: {}", v);
}
}
输出:
An Ok value: 11
An Ok value: 22
An Ok value: 33
可以看出,在那个例子中我们只是跳过了 Err
s。
但是,如果你想处理 Ok
变体 直到你遇到 Err
,如果发生这种情况,只需 return 错误你的函数的调用者,你可以这样做:
fn do_stuff() -> Result<(), MyError> {
let res_values = vec![
Ok(11),
Ok(22),
Err(MyError::new("Foo")),
Ok(33),
];
for r in res_values {
println!("An Ok value: {}", r?);
}
Ok(())
}
输出:
An Ok value: 11
An Ok value: 22
这段代码有两点需要注意。
首先,for
循环可以包含模式。来自 the reference, syntax of for
loops:
Syntax
IteratorLoopExpression :
for
Pattern in
Expressionexcept struct expression BlockExpression
这与 let
语句相同,它们可以在其绑定或函数参数中包含模式。例如。 let _ = ...;
(_
是 wildcard pattern)或 fn f(Struct(v): Struct) {}
(其中 struct Struct(v);
)。
但是,与 match
或 if let
中的模式相反,这些位置中的模式必须是 irrefutable。这意味着模式匹配应该总是成功。
模式 Ok(v)
通常属于枚举 Result<T, E>
,其中 Ok
是变体之一。这意味着它是一个 refutable 模式,这意味着它被禁止在 for
循环中使用。所以这段代码应该是编译时错误。
除非...
此代码有两种工作方式:
第一个是 Ok
名字被你自己的名字遮盖了。例如,
pub struct Ok<T>(pub T);
fn foo(v: Vec<Ok<i32>>) {
for Ok(v /* : i32 */) in v { /* ... */ }
}
第二种情况是 Result
只有一种变体。匹配单变量枚举是无可辩驳的。
但是Result
有两种变体!
有一种特殊的(不稳定的)类型,the never type, denoted !
,意思是“不能存在”。如果我们用 !
填充 Err
变体(这可能是因为 Result
在错误类型上是通用的)...
enum Result<T, !> {
Ok(T),
Err(!),
}
...我们得到一个与以下内容几乎相同的枚举:
enum Result<T> {
Ok(T),
}
即单变体枚举,因为 Err
这种情况永远不存在。
有一个名为 exhaustive_patterns
的不稳定特性,它允许我们将此类情况视为无可辩驳的:
#![feature(never_type, exhaustive_patterns)]
fn foo(v: Vec<Result<i32, !>>) {
for Ok(v /* : i32 */) in v { /* ... */ }
}
(注意:这不仅适用于never类型,也适用于任何其他无误类型,例如std::convert::Infallible
)。
我不明白以下模式的工作原理:
for Ok(value) in do_thing_get_results(){
use_thing(value)
}
循环会忽略 Err
结果吗?它会简单地 .unwrap()
他们并恐慌吗?它是否有另一个用于处理 Err
值的子句,以避免我编写 match
?
适当的 MCVE 给出:
fn the_answer() -> Result<u32, ()> {
Ok(42)
}
fn main() {
for Ok(foo) in Some(the_answer()) {
println!("{}", foo);
}
}
error[E0005]: refutable pattern in `for` loop binding: `Err(_)` not covered
--> src/main.rs:6:9
|
6 | for Ok(foo) in Some(the_answer()) {
| ^^^^^^^ pattern `Err(_)` not covered
|
= note: the matched value is of type `Result<u32, ()>`
Patterns used to bind names must be irrefutable, that is, they must guarantee that a name will be extracted in all cases. If you encounter this error you probably need to use a match or if let to deal with the possibility of failure
您的代码根本无法编译。 Rust 不允许您在 for
循环绑定中使用 refutable patterns。
如果需要,您可以通过多种方式查看 Ok
变体。一种是在 循环中使用 if let
语句 。示例:
let res_values = vec![
Ok(11),
Ok(22),
Err(MyError::new("Foo")),
Ok(33),
];
for r in res_values {
if let Ok(v) = r {
println!("An Ok value: {}", v);
}
}
输出:
An Ok value: 11
An Ok value: 22
An Ok value: 33
可以看出,在那个例子中我们只是跳过了 Err
s。
但是,如果你想处理 Ok
变体 直到你遇到 Err
,如果发生这种情况,只需 return 错误你的函数的调用者,你可以这样做:
fn do_stuff() -> Result<(), MyError> {
let res_values = vec![
Ok(11),
Ok(22),
Err(MyError::new("Foo")),
Ok(33),
];
for r in res_values {
println!("An Ok value: {}", r?);
}
Ok(())
}
输出:
An Ok value: 11
An Ok value: 22
这段代码有两点需要注意。
首先,for
循环可以包含模式。来自 the reference, syntax of for
loops:
Syntax
IteratorLoopExpression :
for
Patternin
Expressionexcept struct expression BlockExpression
这与 let
语句相同,它们可以在其绑定或函数参数中包含模式。例如。 let _ = ...;
(_
是 wildcard pattern)或 fn f(Struct(v): Struct) {}
(其中 struct Struct(v);
)。
但是,与 match
或 if let
中的模式相反,这些位置中的模式必须是 irrefutable。这意味着模式匹配应该总是成功。
模式 Ok(v)
通常属于枚举 Result<T, E>
,其中 Ok
是变体之一。这意味着它是一个 refutable 模式,这意味着它被禁止在 for
循环中使用。所以这段代码应该是编译时错误。
除非...
此代码有两种工作方式:
第一个是 Ok
名字被你自己的名字遮盖了。例如,
pub struct Ok<T>(pub T);
fn foo(v: Vec<Ok<i32>>) {
for Ok(v /* : i32 */) in v { /* ... */ }
}
第二种情况是 Result
只有一种变体。匹配单变量枚举是无可辩驳的。
但是Result
有两种变体!
有一种特殊的(不稳定的)类型,the never type, denoted !
,意思是“不能存在”。如果我们用 !
填充 Err
变体(这可能是因为 Result
在错误类型上是通用的)...
enum Result<T, !> {
Ok(T),
Err(!),
}
...我们得到一个与以下内容几乎相同的枚举:
enum Result<T> {
Ok(T),
}
即单变体枚举,因为 Err
这种情况永远不存在。
有一个名为 exhaustive_patterns
的不稳定特性,它允许我们将此类情况视为无可辩驳的:
#![feature(never_type, exhaustive_patterns)]
fn foo(v: Vec<Result<i32, !>>) {
for Ok(v /* : i32 */) in v { /* ... */ }
}
(注意:这不仅适用于never类型,也适用于任何其他无误类型,例如std::convert::Infallible
)。