То есть, тип Rust never
(!
).
Все есть выражение
Rust — это язык типа «все есть выражение». Выражение — это то, что производит значение. Не все является выражением, но в основном все, что находится в теле Rust (исполняемом коде), является выражением. На самом деле, единственное, что не является выражением, это локали, например:
let x = 5;
Это собственное выражение! Но вы можете иметь выражение с оператором let
, просто возьмите:
if let Some(num) = func_that_returns_option() {}
Оператор 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
возвращаться от этого.