【发布时间】:2022-01-25 14:12:26
【问题描述】:
示例代码sn-p:
fn foo() -> i32 {
let a = return 2;
a + 1
}
fn main() {
println!("{}", foo());
}
我希望因为a 永远不会真正被分配任何东西,它的类型应该是!。但是编译器告诉我它的类型实际上是()(单位类型)。这让我觉得很奇怪。这可能是什么原因?
【问题讨论】:
示例代码sn-p:
fn foo() -> i32 {
let a = return 2;
a + 1
}
fn main() {
println!("{}", foo());
}
我希望因为a 永远不会真正被分配任何东西,它的类型应该是!。但是编译器告诉我它的类型实际上是()(单位类型)。这让我觉得很奇怪。这可能是什么原因?
【问题讨论】:
return 42的类型是!:
break、continue和return表达式也有!类型。例如我们可以这样写:#![feature(never_type)] let x: ! = { return 123 };
来自https://doc.rust-lang.org/std/primitive.never.html。
但! 的一个特点是它可以强制转换为任何类型的值:
fn foo() -> i32 {
let a: String = return 2;
42
}
fn main() {
println!("{}", foo());
}
这就是使之类的事情发生的原因
let num: u32 = match get_a_number() {
Some(num) => num,
None => break,
};
(来自同一页面)。
两个分支必须具有相同的类型。 num 显然是 u32,break 是 !。然后,通过将 break 强制转换为 u32,两者都可以具有相同类型的 u32。
这很好,因为 ! 类型的值永远不会存在,因此编译器可以将其“转换”为任何其他类型的任何值。
在您的示例中出现混淆的地方是编译器将声明“错误[E0277]:无法将i32 添加到()”。这可能是出于历史原因。 ! 在 Rust 1.0 时代并没有这样存在。随着时间的推移,它变得更像一等公民,但为了向后兼容需要一些特殊情况,其中! 将被视为() 而不是任何其他类型。
【讨论】: