発散する関数

発散する関数 (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())の戻り値の型としても使用されます。