Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

発散関数

発散関数は決して戻りません。これらは空の型である ! を使って示されます。

#![allow(unused)]
fn main() {
fn foo() -> ! {
    panic!("この呼び出しは決して戻りません。");
}
}

他のすべての型とは異なり、この型はインスタンス化できません。なぜなら、この型が取り得るすべての可能な値の集合は空だからです。これは、取り得る値が正確に 1 つだけある () 型とは異なることに注意してください。

たとえば、この関数は通常どおり戻りますが、戻り値には情報がありません。

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 未満(9 を含まない)の奇数の合計: {}", sum_odd_numbers(9));
}

これはまた、ネットワークサーバーのように永遠にループする関数(例: loop {})や、プロセスを終了させる関数(例: exit())の戻り値の型でもあります。