発散する関数

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