[英]What is the point of diverging functions in Rust?
我已经阅读了几个关于 SO 的答案,并收集了这些用例:
panic!
s但我仍然不清楚为什么我们需要像这样定义 function:
fn func() -> ! {
panic!("Error!");
}
如果它的工作方式与此相同(没有感叹号):
fn func() {
panic!("Error!");
}
同时,为什么我们需要使用!
在具有无限循环的函数中? 看起来这个签名并没有带来任何真实的使用信息。
这些签名之间的主要区别归结为一个事实!
可以强制转换为任何其他类型,因此与任何其他类型兼容(由于从未采用此代码路径,我们可以假设它是我们需要的任何类型)。 当我们有多个可能的代码路径时,这一点很重要,例如if-else
或match
。
例如,考虑以下(可能是人为的,但希望足够清晰)代码:
fn assert_positive(v: i32) -> u32 {
match v.try_into() {
Ok(v) => v,
Err(_) => func(),
}
}
当func
被声明返回时!
,这个function 编译成功。 如果我们删除返回类型, func
将被声明为返回()
,并且编译中断:
error[E0308]: `match` arms have incompatible types
--> src/main.rs:8:19
|
6 | / match v.try_into() {
7 | | Ok(v) => v,
| | - this is found to be of type `u32`
8 | | Err(_) => func(),
| | ^^^^^^ expected `u32`, found `()`
9 | | }
| |_____- `match` arms have incompatible types
您还可以将其与Result::unwrap
的定义进行比较:
pub fn unwrap(self) -> T {
match self {
Ok(t) => t,
Err(e) => unwrap_failed("called `Result::unwrap()` on an `Err` value", &e),
}
}
在这里, unwrap_failed
正在返回!
,因此它与Ok
情况下返回的任何类型相统一。
编译器知道遵循发散表达式(w.r.t. 评估顺序)的任何内容都是不可达的。 在决定是否初始化局部变量时,它可以使用此信息来避免误报。
考虑以下示例:
use rand; // 0.8.4
fn main() {
let foo;
if rand::random::<bool>() {
foo = "Hello, world!";
} else {
diverge();
}
println!("{foo}");
}
fn diverge() {
panic!("Crash!");
}
我们声明了一个变量foo
,但我们只在if
表达式的一个分支中初始化它。 这无法编译并出现以下错误:
error[E0381]: borrow of possibly-uninitialized variable: `foo`
--> src/main.rs:10:15
|
10 | println!("{foo}");
| ^^^^^ use of possibly-uninitialized `foo`
但是,如果我们像这样改变我们的diverge
function 的定义:
fn diverge() -> ! {
panic!("Crash!");
}
然后代码成功编译。 编译器知道如果使用else
分支,它永远不会到达println!
因为diverge()
发散。 因此, else
分支没有初始化foo
并不是错误。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.