Расходящиеся функции
Расходящиеся функции никогда не возвращают результат. Они помечены с помощью !
, который является пустым типом.
#![allow(unused)] fn main() { fn foo() -> ! { panic!("Этот вызов никогда не вернёт управление."); } }
В отличие от всех других типов, этот не может быть создан, потому что
набор всех возможных значений этого типа пуст. Обратите
внимание, что он отличается от типа ()
, который
имеет ровно одно возможное значение.
Например, эта функция имеет возвращаемое значение, хотя о нём нет информации.
fn some_fn() { () } fn main() { let a: () = some_fn(); println!("Эта функция возвращает управление и вы можете увидеть эту строку.") }
В отличие от этой функции, которая никогда не вернёт элемент управления вызывающей стороне.
#![feature(never_type)]
fn main() {
let x: ! = panic!("Этот вызов никогда не вернёт управление.");
println!("вы никогда не увидете эту строку!");
}
Хотя это может показаться абстрактным понятием, на самом деле
это очень полезно и может пригодится. Главное преимущество
этого типа в том, что его можно привести к любому другому типу и
поэтому используется в местах, где требуется точный тип,
например в ветвях match
. Это позволяет нам писать
такой код:
fn main() { fn sum_odd_numbers(up_to: u32) -> u32 { let mut acc = 0; for i in 0..up_to { // Обратите внимание, что возвращаемый тип этого выражения match должен быть u32 // потому что такой тип в переменной "addition" . let addition: u32 = match i%2 == 1 { // Переменная "i" типа u32, что совершенно нормально. true => i, // С другой стороны выражение "continue" не возвращает // u32, но это тоже нормально, потому что это тип не возвращающий управление, // не нарушает требования к типу выражения match. false => continue, }; acc += addition; } acc } println!("Сумма нечётных чисел до 9 (исключая): {}", sum_odd_numbers(9)); }
Это также возвращаемый тип функций, которые содержат вечный
цикл (например, loop {}
), как сетевые серверы или
функции, завершающие процесс (например, exit()
).