発散する関数
発散する関数 (Diverging functions) は決してリターンしない関数です。こうした関数は !
を使って、空の型であることが示されます。
#![allow(unused)] fn main() { fn foo() -> ! { // この呼び出しは決してリターンしない。 panic!("This call never returns."); } }
他の全ての型と異なり、この型はインスタンス化できません。
この型が持ちうる全ての値の集合は空です。
この型は()
型とは異なることに注意してください。
()
型は値をただ1つだけ持つ型です。
例えば、この関数は通常どおりリターンしますが、戻り値には何の情報も含みません。
fn some_fn() { () } fn main() { let _a: () = some_fn(); // この関数はリターンするので、この行は実行される。 println!("This function returns and you can see this line."); }
一方、この関数は呼び出し元に決してリターンしません。
#![feature(never_type)]
fn main() {
// この呼び出しは決してリターンしない。
let x: ! = panic!("This call never returns.");
// この行は決して実行されない。
println!("You will never see this line!");
}
これは抽象的な概念に見えるかもしれませんが、実際のところはとても実用的で、便利なことも多いのです。
この型の主な利点は、他のどのような型にもキャストできることです。
そのため、例えばmatch
の分岐の中のような正確な型が要求される場所でも使用できます。
fn main() { fn sum_odd_numbers(up_to: u32) -> u32 { let mut acc = 0; for i in 0..up_to { // Notice that the return type of this match expression must be u32 // because of the type of the "addition" variable. // 変数"addition"の型がu32であるため、 // このmatch式はu32をリターンしなければならないことに注意。 let addition: u32 = match i%2 == 1 { // The "i" variable is of type u32, which is perfectly fine. // 変数"i"はu32型であるため、全く問題ない。 true => i, // On the other hand, the "continue" expression does not return // u32, but it is still fine, because it never returns and therefore // does not violate the type requirements of the match expression. // 一方、"continue"式はu32をリターンしないが、これでも問題ない。 // 決してリターンしないため、このmatch式が要求する型に違反しないからである。 false => continue, }; acc += addition; } acc } println!("Sum of odd numbers up to 9 (excluding): {}", sum_odd_numbers(9)); }
この型は、ネットワークサーバのような永遠にループする関数(例:loop {}
)の戻り値の型や、プロセスを終了させる関数(例:exit()
)の戻り値の型としても使用されます。