Означает ли это сообщение об ошибке, что я могу использовать сопоставление шаблонов для циклов?
Я не ожидаю, что следующий код будет работать, но в рамках изучения грамматики я попытался на игровой площадке:
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
дела Err
. Но какова правильная грамматика?
Ответы
Ответ 1
Вы можете использовать шаблоны в качестве привязки в цикле for
, но не шаблоны с опровержением. Здесь описывается различие между опровержимыми и неопровержимыми шаблонами, но суть в том, что если шаблон может потерпеть неудачу, его нельзя использовать в операторе let
или цикле for
. Если шаблон не может потерпеть неудачу, вы не можете (в настоящее время) использовать его в if let
или while let
. (Последнее может быть изменено в будущей версии, чтобы выдавать предупреждение вместо сбоя.)
Пример неопровержимого шаблона, используемого в цикле 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)
- неопровержимый шаблон, потому что в любом месте, где он проверяет тип, он будет совпадать. Здесь он проверяет тип, потому что элементы, которые перебираются (определены реализацией IntoIterator
для &HashMap
), являются кортежами. Вы также можете написать выше как
for tuple in &numbers {
let (name, number) = tuple;
println!("{}: {}", name, number);
}
потому что let
- это другое место, где разрешены только неопровержимые образцы.
Ответ 2
Да, вы можете использовать шаблоны во многих местах, но не все из них позволяют условно переходить, когда существует несколько возможных шаблонов.
Цикл 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);
}
}
Условный:
Безусловный:
for
let
- параметры функции
Ответ 3
Но какова правильная грамматика?
Это дает результат, который вы хотите:
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
реализует метод into_iter
предоставляемый признаком IntoIterator
.
Это еще один вариант, 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);
}
}