此错误消息是否意味着我可以在 for 循环中使用模式匹配?



我不希望以下代码起作用,但作为语法探索的一部分,我在操场上尝试过:

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)是一个无可辩驳的模式,因为它键入检查的任何地方,它都会匹配。它在这里进行类型检查,因为迭代的项目(由&HashMapIntoIterator实现定义(是元组。你也可以把上面写成

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);
}
}

最新更新