Ale*_*vik 21 function panic rust
我已经阅读了几个关于 SO 的答案,并收集了这些用例:
panic!函数但我仍然不清楚为什么我们需要这样定义函数:
fn func() -> ! {
panic!("Error!");
}
Run Code Online (Sandbox Code Playgroud)
如果它的工作方式与此相同(没有感叹号):
fn func() {
panic!("Error!");
}
Run Code Online (Sandbox Code Playgroud)
同时,为什么我们需要!在具有无限循环的函数中使用?看起来这个签名并没有带来任何真实的使用信息。
Cer*_*rus 37
这些签名之间的主要区别归结为!可以强制转换为任何其他类型,因此与任何其他类型兼容(因为从未采用此代码路径,所以我们可以假设它是我们需要的任何类型)。当我们有多个可能的代码路径(例如if-else或 )时,这一点很重要match。
例如,考虑以下(可能是人为的,但希望足够清晰)代码:
fn assert_positive(v: i32) -> u32 {
match v.try_into() {
Ok(v) => v,
Err(_) => func(),
}
}
Run Code Online (Sandbox Code Playgroud)
当func声明为 return时!,该函数编译成功。如果我们删除返回类型,func将被声明为 returned (),并且编译会中断:
fn assert_positive(v: i32) -> u32 {
match v.try_into() {
Ok(v) => v,
Err(_) => func(),
}
}
Run Code Online (Sandbox Code Playgroud)
您还可以将其与 的定义Result::unwrap进行比较:
pub fn unwrap(self) -> T {
match self {
Ok(t) => t,
Err(e) => unwrap_failed("called `Result::unwrap()` on an `Err` value", &e),
}
}
Run Code Online (Sandbox Code Playgroud)
这里,unwrap_failed是returning!,所以它与万一返回的任何类型统一Ok。
Fra*_*gné 14
编译器知道发散表达式(求值顺序)后面的任何内容都是无法访问的。在决定局部变量是否初始化时,它可以使用此信息来避免误报。
考虑以下示例:
use rand; // 0.8.4
fn main() {
let foo;
if rand::random::<bool>() {
foo = "Hello, world!";
} else {
diverge();
}
println!("{foo}");
}
fn diverge() {
panic!("Crash!");
}
Run Code Online (Sandbox Code Playgroud)
我们声明了一个变量foo,但我们只在if表达式的一个分支中初始化它。无法编译并出现以下错误:
use rand; // 0.8.4
fn main() {
let foo;
if rand::random::<bool>() {
foo = "Hello, world!";
} else {
diverge();
}
println!("{foo}");
}
fn diverge() {
panic!("Crash!");
}
Run Code Online (Sandbox Code Playgroud)
diverge但是,如果我们像这样更改函数的定义:
fn diverge() -> ! {
panic!("Crash!");
}
Run Code Online (Sandbox Code Playgroud)
然后代码编译成功。编译器知道,如果else采用分支,它永远不会到达,println!因为diverge()存在分歧。else因此,分支未初始化并不是错误foo。
| 归档时间: |
|
| 查看次数: |
1625 次 |
| 最近记录: |