Почему вы можете использовать ранее необъявленное имя в матче? - PullRequest
4 голосов
/ 29 марта 2019

У меня проблема с пониманием этого кода из второй главы книги:

let guess: u32 = match guess.trim().parse() {
    Ok(num) => num,
    Err(_) => continue,
};

Моя проблема с Ok(num) => num: parse() возвращает значение (Ok или Err), match сравнивает это возвращенное значение с первым рычагом. Если они совпадают, выражение выполнит оператор рядом с первой рукой, верно?

В Ok(num), num, кажется, неожиданно появился, поскольку в предыдущем коде не было объявления num. То же самое с утверждением, => num: num внезапно оказался в области видимости. Так

  1. Если я угадываю это правильно, match сопоставляет возвращаемое значение с Ok(), а затем присваивает любой номер (внутри Ok) num. Но почему num справа вдруг можно использовать?
  2. Если я правильно угадал, в чем разница Ok(num) и Ok(_)?

Ответы [ 2 ]

9 голосов
/ 29 марта 2019

Если мы начнем с того, откуда взялись Ok и Err, мы могли бы получить лучшую идею. Они являются частью перечисления Result, определенного как:

enum Result<T, E> {
   Ok(T),
   Err(E),
}

T и E являются общими типами. match сам по себе похож на оператор C switch, но более гибкий.

Общая форма match сама по себе:

match value {
    pattern => expr,
    ...
}

Если они совпадают, выражение выполнит оператор рядом с первой рукой, верно?

Да

Но почему num справа вдруг можно использовать?

Потому что match соответствует шаблонам слева от => в каждой руке. Может распаковывать кортежи, сопоставлять структурные поля, брать части значения и т. Д.

Если я правильно угадал, в чем разница Ok(num) и Ok(_)?

_ является шаблоном подстановки и соответствует всему.

Разница между Ok(num) и Ok(_) заключается в том, что в первом случае вы спрашиваете, что если Result является вариантом Ok, то сохраните его значение типа T в num. Во втором случае вы говорите, что вам все равно, какое значение имеет Ok - до тех пор, пока Result - это вариант Ok, который вы хотите выполнить.

Помните, что когда вы используете _ в шаблоне, вы не можете использовать _ внутри кода, т. Е. Это не будет работать, потому что _ не является идентификатором:

let guess: u32 = match guess.trim().parse() {
    Ok(_) => _,
    Err(_) => continue,
};
0 голосов
/ 29 марта 2019

короткий ответ.patterns match может разрушать структуры, перечисления ... см. Здесь

подпись parse равна pub fn parse<F>(&self) -> Result<F, <F as FromStr>::Err>.В нем есть универсальный тип F.

Компилятор находит let guess: u32 =, и он делает вывод, что вам нужно u32.Таким образом, F здесь u32.

Тогда шаблоны соответствуют разрушающим экстрактам num из Ok<u32>

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...