发散函数

发散函数永不返回。它们使用 ! 标记,这是一个空类型。

#![allow(unused)]
fn main() {
fn foo() -> ! {
    panic!("此调用永不返回。");
}
}

与所有其他类型相反,这个类型不能被实例化,因为这个类型可能拥有的所有可能值的集合是空的。注意,它与 () 类型不同,后者恰好有一个可能的值。

例如,这个函数像往常一样返回,尽管返回值中没有任何信息。

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" 变量的类型是 u32。
            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())。