我不希望以下代码起作用,但作为语法探索的一部分,我在操场上尝试过:
fn main() {
struct EOF {};
let lines = vec![Ok("line 1"), Ok("line 2"), Err(EOF {})];
for Ok(line) in lines {
println!("{}", line);
}
}
错误消息是
error[E0005]: refutable pattern in `for` loop binding: `Err(_)` not covered
--> src/main.rs:4:9
|
4 | for Ok(line) in lines {
| ^^^^^^^^ pattern `Err(_)` not covered
根据上面的消息,看起来我只需要为Err
的情况添加一个火柴臂。但是这样做的正确语法是什么?
> 您可以使用模式作为for
循环中的绑定,但不能使用可反驳的模式。这里描述了可反驳模式和无可辩驳模式之间的区别,但它的要点是,如果模式可能失败,则不能在let
语句、for
循环、函数或闭包的参数或语法特别需要无可辩驳模式的其他地方使用它。
在for
循环中使用的无可辩驳模式的示例可能是这样的:
let mut numbers = HashMap::new();
numbers.insert("one", 1);
numbers.insert("two", 2);
numbers.insert("three", 3);
for (name, number) in &numbers {
println!("{}: {}", name, number);
}
(name, number)
是一个无可辩驳的模式,因为它键入检查的任何地方,它都会匹配。它在这里进行类型检查,因为迭代的项目(由&HashMap
的IntoIterator
实现定义(是元组。你也可以把上面写成
for tuple in &numbers {
let (name, number) = tuple;
println!("{}: {}", name, number);
}
因为let
是另一个只允许无可辩驳的模式的地方。
是的,您可以在许多地方使用模式,但并非所有模式都允许您在存在多种可能的模式时有条件地分支。
for
循环是无法添加条件的地方。这就是错误用"可反驳模式"告诉你的:有一种模式不会被处理。相反,您主要使用该模式来执行循环变量的解构:
struct Thing {
foo: u8,
}
fn main() {
let things = vec![Thing { foo: 1 }, Thing { foo: 2 }, Thing { foo: 3 }];
for Thing { foo } in things {
println!("{}", foo);
}
}
有條件的:
match
if let
while let
无条件的:
for
let
- 函数参数
的正确语法是什么?
这将得到您想要的结果:
fn main() {
struct EOF;
let lines = vec![Ok("line 1"), Ok("line 2"), Err(EOF)];
for line in lines.into_iter().flat_map(|e| e) {
println!("{}", line);
}
}
请注意,您可以在此处使用flat_map
,因为Result
实现了IntoIterator
特征提供的into_iter
方法。
这是使用if let
的另一个选项:
fn main() {
struct EOF;
let lines = vec![Ok("line 1"), Ok("line 2"), Err(EOF)];
for result in lines {
if let Ok(line) = result {
println!("{}", line);
}
}
}
您可能还希望停止对Err
事例的迭代:
fn main() {
struct EOF;
let lines = vec![Ok("line 1"), Ok("line 2"), Err(EOF), Ok("line 3") ];
let mut lines_iter = lines.into_iter();
while let Some(Ok(line)) = lines_iter.next() {
println!("{}", line);
}
}