発散する関数
発散する関数は決してリターンしない関数です。こうした関数は !
を使って、空の型であることが示されます。
#![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 { // 変数"addition"の型がu32であるため、 // このmatch式はu32をリターンしなければならないことに注意。 let addition: u32 = match i%2 == 1 { // 変数"i"はu32型であるため、全く問題ありません。 true => i, // 一方、"continue"式はu32をリターンしませんが、これでも問題ありません。 // 決してリターンしないため、このmatch式が要求する型に違反しないからです。 false => continue, }; acc += addition; } acc } println!("Sum of odd numbers up to 9 (excluding): {}", sum_odd_numbers(9)); }
この型は、ネットワークサーバのような永遠にループする関数(例:loop {}
)の戻り値の型や、プロセスを終了させる関数(例:exit()
)の戻り値の型としても使用されます。