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 diverges() -> ! {
    panic!("This function never returns!");
}

fn example() {
    let x: i32 = diverges(); // 这一行永远不会完成。
    println!("This is never printed: {x}");
}
}

有关特定表达式发散行为的规则,请参见:

Note

panic! 宏以及相关的生成 panic 的宏(如 unreachable!)也具有类型 ! 并且是发散的。

任何类型为 ! 的表达式都是发散表达式。然而,发散表达式不限于类型 !;其他类型的表达式也可能发散(例如,Some(loop {}) 的类型是 Option<!>)。

Note

尽管 ! 被视为无人居住类型,但类型是无人居住的并不足以使其发散。

#![allow(unused)]
fn main() {
enum Empty {}
fn make_never() -> ! {loop{}}
fn make_empty() -> Empty {loop{}}

fn diverging() -> ! {
    // 此处的类型为 `!`。
    // 因此,整个函数被认为是发散的。
    make_never();
    // 正确:函数体的类型是 `!`,与返回类型匹配。
}
fn not_diverging() -> ! {
    // 此类型是无人居住的。
    // 然而,整个函数不被认为是发散的。
    make_empty();
    // 错误:函数体的类型是 `()`,但期望的类型是 `!`。
}
}

Note

发散可以传播到外围的块。请参见 expr.block.diverging

回退

如果待推断的类型仅与发散表达式统一,那么该类型将被推断为 !

Example

#![allow(unused)]
fn main() {
fn foo() -> i32 { 22 }
match foo() {
    // 错误:trait 约束 `!: Default` 未满足。
    4 => Default::default(),
    _ => return,
};
}

2024 Edition differences

在 2024 版次之前,该类型被推断为 ()

Note

重要的是,类型统一可能以结构化方式发生,因此回退到的 ! 可能是更大类型的一部分。以下代码可以编译:

#![allow(unused)]
fn main() {
fn foo() -> i32 { 22 }
// 此处的类型为 `Option<!>`,而非 `!`
match foo() {
    4 => Default::default(),
    _ => Some(return),
};
}