Rust никогда этого не сделает!

То есть, тип Rust never (!).

Все есть выражение

Rust — это язык типа «все есть выражение». Выражение — это то, что производит значение. Не все является выражением, но в основном все, что находится в теле Rust (исполняемом коде), является выражением. На самом деле, единственное, что не является выражением, это локали, например:

let x = 5;
Войти в полноэкранный режим Выйти из полноэкранного режима

Это собственное выражение! Но вы можете иметь выражение с оператором let, просто возьмите:


if let Some(num) = func_that_returns_option() {}
Enter fullscreen mode Выйти из полноэкранного режима

Оператор let здесь не является локальным, это выражение let.

Давайте рассмотрим еще несколько вещей, которые также являются выражениями:

{ 1 }
Войти в полноэкранный режим Выход из полноэкранного режима
loop { break 1; }
Войти в полноэкранный режим Выход из полноэкранного режима
if true { 1 } else { return; }
Войти в полноэкранный режим Выход из полноэкранного режима

Последнее нас интересует больше всего.

Тип never.

Итак, если мы посмотрим на последний пример, который я привел, вы знаете, что блок if оценивается в 1. Но как насчет блока else? return; не выдает значение, он фактически покидает функцию. Так каков же его тип?

Правильно, тип never!

Смысл типа never в том, чтобы сказать: «Это вычисление не завершится». Таким образом, если вы присвоите что-то этому значению:

let x = if true { 1 } else { return; }
Войти в полноэкранный режим Выйти из полноэкранного режима

Тип x основан на блоке if. Но это не означает, что тип never игнорируется. Компилятор понимает это так: never может быть принудительно приведен к любому типу. То есть, пытаясь определить тип для x, компилятор видит, что блок if имеет тип i32. Затем блок else имеет тип never, поэтому, чтобы сделать его последовательным, он говорит «never может преобразоваться в i32» и все в порядке!

Что это значит для пользователя?

Ну, не очень много. В основном это забавная хитрость компилятора. Но если вы хотите, чтобы это упоминалось в диагностике, попробуйте новый синтаксис let else (в настоящее время доступен только в nightly). Этот синтаксис позволяет использовать шаблон для привязки let, который не всегда может быть истинным, например:

let Ok(x) = returns_result() else { warn!("This is bad!"); return; };
Войти в полноэкранный режим Выйти из полноэкранного режима

Так, если returns_result возвращает Ok, то мы присваиваем x значению в Ok. Но если это не так, мы предупреждаем и возвращаем. Довольно просто!

Однако тип этого блока else должен быть never.

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

#![feature(let_else)]

fn opt() -> Option<i32> {
    Some(1)
}

fn main() {
    let Some(x) = opt() else { 1 };
}
Войти в полноэкранный режим Выйти из полноэкранного режима

Это приведет к ошибке:

error[E0308]: `else` clause of `let...else` does not diverge
 --> letelse.rs:7:30
  |
7 |     let Some(x) = opt() else { 1 };
  |                              ^^^^^ expected `!`, found integer
  |
  = note: expected type `!`
             found type `{integer}`
  = help: try adding a diverging expression, such as `return` or `panic!(..)`
  = help: ...or use `match` instead of `let...else`

error: aborting due to previous error

For more information about this error, try `rustc --explain E0308`.
Войти в полноэкранный режим Выйти из полноэкранного режима

Мы ожидаем, что блок else будет расходиться, поэтому он должен быть типа never!

Круто.

Rust будет never возвращаться от этого.

Оцените статью
devanswers.ru
Добавить комментарий