! 其中 ! 是 "Never" primitive type . 为什么 Rust 为此-6ren">
gpt4 book ai didi

types - 为什么 Rust 有一个 "Never"原始类型?

转载 作者:行者123 更新时间:2023-11-29 07:45:02 28 4
gpt4 key购买 nike

Rust 的 std::process::exit有类型

pub fn exit(code: i32) -> !

其中 !"Never" primitive type .

为什么 Rust 为此需要一个特殊类型?

将其与 Haskell 进行比较,其中 System.Exit.exitWith 的类型是

exitWith :: forall a. Int -> a

相应的 Rust 签名是

pub fn exit<T>(code: i32) -> T

没有必要为不同的 T 单态化这个函数,因为 T 永远不会具体化,所以编译应该仍然有效。

最佳答案

TL;DR:因为它支持本地推理和可组合性。

您关于替换 exit() -> ! 的想法通过 exit<T>() -> T只考虑类型系统和类型推断。你是对的,从类型推断的角度来看,两者是等价的。然而,语言不仅仅是类型系统。

无意义代码的局部推理

! 的存在允许本地推理来检测无意义的代码。例如,考虑:

use std::process::exit;

fn main() {
exit(3);
println!("Hello, World");
}

编译器立即标记 println!声明:

warning: unreachable statement
--> src/main.rs:5:5
|
5 | println!("Hello, World");
| ^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: #[warn(unreachable_code)] on by default
= note: this error originates in a macro outside of the current crate
(in Nightly builds, run with -Z external-macro-backtrace for more info)

如何?嗯,exit的签名清楚地表明它永远不会返回,因为没有 ! 的实例永远不会被创建,因此它之后的任何东西都不可能被执行。

优化的局部推理

类似地,rustc 传递有关 exit 签名的信息。到 LLVM 优化器。

首先在exit的声明中:

; std::process::exit
; Function Attrs: noreturn
declare void @_ZN3std7process4exit17hcc1d690c14e39344E(i32) unnamed_addr #5

然后在使用现场,以防万一:

; playground::main
; Function Attrs: uwtable
define internal void @_ZN10playground4main17h9905b07d863859afE() unnamed_addr #0 !dbg !106 {
start:
; call std::process::exit
call void @_ZN3std7process4exit17hcc1d690c14e39344E(i32 3), !dbg !108
unreachable, !dbg !108
}

可组合性

在 C++ 中,[[noreturn]]是一个属性。这真的很不幸,因为它没有与通用代码集成:对于有条件的 noreturn你需要经历的函数,以及选择noreturn的方法类型与使用一个库的类型一样多。

在 Rust 中,!是一流的构造,在所有库中都是统一的,最重要的是……即使是在没有 ! 的情况下创建的库记住就可以了。

最好的例子是 Result类型(Haskell 的 Either )。它的完整签名是 Result<T, E>其中 T是预期的类型并且 E错误类型。 ! 没有什么特别的在Result , 但它可以用 ! 实例化:

#![feature(never_type)]

fn doit() -> Result<i32, !> { Ok(3) }

fn main() {
doit().err().unwrap();
println!("Hello, World");
}

编译器直接看穿了它:

warning: unreachable statement
--> src/main.rs:7:5
|
7 | println!("Hello, World");
| ^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: #[warn(unreachable_code)] on by default
= note: this error originates in a macro outside of the current crate
(in Nightly builds, run with -Z external-macro-backtrace for more info)

可组合性(之二)

推理无法实例化的类型的能力也扩展到推理无法实例化的枚举变体。

例如,编译以下程序:

#![feature(never_type, exhaustive_patterns)]

fn doit() -> Result<i32, !> {
Ok(3)
}

fn main() {
match doit() {
Ok(v) => println!("{}", v),
// No Err needed
}

// `Ok` is the only possible variant
let Ok(v) = doit();
println!("{}", v);
}

通常,Result<T, E>有两个变体:Ok(T)Err(E) ,因此匹配必须考虑到这两种变体。

然而,在这里,因为 !无法实例化,Err(!)不可能,因此 Result<T, !>有一个变体:Ok(T) .因此,编译器只允许考虑 Ok案例。

结论

编程语言的类型系统远不止于此。

编程语言是指开发人员将其意图 传达给其他开发人员和机器。 Never 类型使开发者的意图清晰,让其他方清楚地理解开发者的意思,而不必从偶然的线索中重构意思。

关于types - 为什么 Rust 有一个 "Never"原始类型?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51832396/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com