繁体   English   中英

Rust 中的不同功能有什么意义?

[英]What is the point of diverging functions in Rust?

我已经阅读了几个关于 SO 的答案,并收集了这些用例:

  • 当一个 function panic! s
  • 当 function 中有一个无限循环时

但我仍然不清楚为什么我们需要像这样定义 function:

fn func() -> ! {
    panic!("Error!");
}

如果它的工作方式与此相同(没有感叹号):

fn func() {
    panic!("Error!");
}

同时,为什么我们需要使用! 在具有无限循环的函数中? 看起来这个签名并没有带来任何真实的使用信息。

这些签名之间的主要区别归结为一个事实! 可以强制转换为任何其他类型,因此与任何其他类型兼容(由于从未采用此代码路径,我们可以假设它是我们需要的任何类型)。 当我们有多个可能的代码路径时,这一点很重要,例如if-elsematch

例如,考虑以下(可能是人为的,但希望足够清晰)代码:

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM