Primitive Type never[]

🔬 This is a nightly-only experimental API. (never_type #35121)
Expand description

! 类型,也称为 “never”。

! 表示永远不会解析为任何值的计算类型。 例如,exit 函数 fn exit(code: i32) -> ! 退出该进程而不返回,因此返回 !

breakcontinuereturn 表达式也具有 ! 类型。例如,我们可以写:

#![feature(never_type)]
let x: ! = {
    return 123
};
Run

尽管 let 在这里毫无意义,但它说明了 ! 的含义。 由于从未给 x 赋值 (因为 return 从整个函数返回),因此可以给 x 指定 ! 类型。 我们也可以将 return 123 替换为 panic! 或永无休止的 loop,并且此代码仍然有效。

以下代码更实际地使用 !

let num: u32 = match get_a_number() {
    Some(num) => num,
    None => break,
};
Run

两个匹配分支都必须产生 u32 类型的值,但是由于 break 根本不会产生值,我们知道它永远不会产生不是 u32 的值。

这说明了 ! 类型的另一种行为 - 类型为 ! 的表达式将强制转换为任何其他类型。

! 和泛型

绝对的错误

您将看到显式使用的 ! 的主要位置是泛型代码。考虑 FromStr trait:

trait FromStr: Sized {
    type Err;
    fn from_str(s: &str) -> Result<Self, Self::Err>;
}
Run

当为 String 实现此 trait 时,我们需要为 Err 选择一个类型。并且由于将字符串转换为字符串永远不会导致错误,因此适当的类型是 !。 (目前实际使用的类型是一个没有变体的枚举,尽管这只是因为 ! 以后才会被添加到 Rust 中,并且将来可能会发生变化。) 对于 Err 类型的 !,如果我们由于某种原因不得不调用 String::from_str,那么结果将是 Result<String, !>,我们可以像这样解包:

#![feature(exhaustive_patterns)]
use std::str::FromStr;
let Ok(s) = String::from_str("hello");
Run

由于 Err 变体包含 !,因此永远不会发生。如果存在 exhaustive_patterns 特性,则意味着我们只需采用 Ok 变体就可以在 Result<T, !> 上进行穷尽的匹配。 这说明了 ! 的另一种行为 - 它可以用于 “delete” 泛型 (如 Result) 中的某些枚举变体。

无限循环

尽管 Result<T, !> 对于消除错误非常有用,但 ! 也可以用于消除成功。如果我们将 Result<T, !> 视为 “if this function returns, it has not errored,”,那么我们也会非常直观地想到 Result<!, E>: 如果函数返回,则 错误。

例如,考虑一个简单的 Web 服务器的情况,它可以简化为:

loop {
    let (client, request) = get_request().expect("disconnected");
    let response = request.process();
    response.send(client);
}
Run

目前,这并不理想,因为只要无法建立新的连接,我们就简单地使用 panic。 相反,我们想跟踪此错误,如下所示:

loop {
    match get_request() {
        Err(err) => break err,
        Ok((client, request)) => {
            let response = request.process();
            response.send(client);
        },
    }
}
Run

现在,当服务器断开连接时,我们以错误退出循环而不是 panic。虽然简单地返回错误可能很直观,但我们可能希望将其包装在 Result<!, E> 中:

fn server_loop() -> Result<!, ConnectionError> {
    loop {
        let (client, request) = get_request()?;
        let response = request.process();
        response.send(client);
    }
}
Run

现在,我们可以使用 ? 代替 match,并且返回类型更有意义:如果循环停止,则意味着发生了错误。我们甚至不必将循环包装在 Ok 中,因为 ! 会自动强制转换为 Result<!, ConnectionError>

! 和 traits

编写自己的 traits 时,只要有明显的 impl 而不是 panic!! 就应该有一个 impl。 原因是返回 impl Trait! 没有 impl 的函数不能作为它的唯一可能的代码路径发散。 换句话说,它们不能从每个代码路径返回 !。 例如,此代码不会编译:

use std::ops::Add;

fn foo() -> impl Add<u32> {
    unimplemented!()
}
Run

但是这段代码可以做到:

use std::ops::Add;

fn foo() -> impl Add<u32> {
    if true {
        unimplemented!()
    } else {
        0
    }
}
Run

原因是,在第一个示例中,! 可以强制转换为许多可能的类型,因为许多类型实现了 Add<u32>。 但是,在第二个示例中,else 分支返回 0,编译器从返回类型推断出它为 u32 类型。 由于 u32 是具体类型,因此 ! 可以并且将被强制使用。 有关此 ! 的更多信息,请参见问题 #36375

但是,事实证明,大多数 traits 都可以将 impl 用作 !。以 Debug 为例:

#![feature(never_type)]
impl Debug for ! {
    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
        *self
    }
}
Run

我们再次使用 ! 的功能来强制转换为任何其他类型,在本例中为 fmt::Result。 由于此方法将 &! 作为参数,因此我们知道它永远不能被调用 (因为没有 ! 类型的值可以调用它)。 编写 *self 实质上就是告诉编译器 “我们知道这段代码永远无法运行,所以只需将整个函数体视为具有类型 fmt::Result”。 当为 ! 实现 traits 时,可以使用这种模式。 通常,任何仅具有采用 self 参数的方法的 trait 都应具有这样的含义。

另一方面,不适合实现的一个 trait 是 Default

trait Default {
    fn default() -> Self;
}
Run

由于 ! 没有值,因此也没有默认值。 的确,我们可以为此编写一个 impl,它只是 panics,但是对于任何类型都一样 (我们可以通过仅将 default() panic 制作为 (eg.) File 来使用 impl Default)。

Trait Implementations

返回值的副本。 Read more

source 执行复制分配。 Read more

使用给定的格式化程序格式化该值。 Read more

使用给定的格式化程序格式化该值。 Read more

此错误的下级来源 (如果有)。 Read more

🔬 This is a nightly-only experimental API. (backtrace #53487)

返回发生错误的栈回溯 (如果有)。 Read more

👎 Deprecated since 1.42.0:

use the Display impl or to_string()

👎 Deprecated since 1.33.0:

replaced by Error::source, which can support downcasting

将该值输入给定的 HasherRead more

将这种类型的切片送入给定的 Hasher 中。 Read more

此方法返回 selfother 之间的 OrderingRead more

比较并返回两个值中的最大值。 Read more

比较并返回两个值中的最小值。 Read more

将值限制在某个时间间隔内。 Read more

此方法测试 selfother 值是否相等,并由 == 使用。 Read more

此方法测试 !=

如果存在,则此方法返回 selfother 值之间的顺序。 Read more

此方法测试的内容少于 (对于 selfother),并且由 < 操作员使用。 Read more

此方法测试小于或等于 (对于 selfother),并且由 <= 运算符使用。 Read more

此方法测试大于 (对于 selfother),并且由 > 操作员使用。 Read more

此方法测试是否大于或等于 (对于 selfother),并且由 >= 运算符使用。 Read more

🔬 This is a nightly-only experimental API. (termination_trait_lib #43301)

被调用以获取值的表示形式作为状态码。 此状态代码返回到操作系统。 Read more