Означает ли это сообщение об ошибке, что я могу использовать сопоставление с шаблоном для циклов? - PullRequest
0 голосов
/ 01 июня 2018

Я не ожидаю, что следующий код будет работать, но в рамках исследования грамматики я попытался на plays :

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.Но какая грамматика подходит для этого?

Ответы [ 3 ]

0 голосов
/ 01 июня 2018

Вы можете использовать шаблоны в качестве привязки в цикле 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 - это другое место, где разрешены только неопровержимые образцы.

0 голосов
/ 01 июня 2018

Но какова правильная грамматика для этого?

Это дает желаемый результат:

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);
    }
}
0 голосов
/ 01 июня 2018

Да, вы можете использовать шаблоны во многих местах , но не все из них позволяют условно переходить при наличии нескольких возможных шаблонов.

Цикл 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
  • параметры функции
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...