如何静态断言函数的结束是无法访问的



我在函数末尾有一个相当复杂的match语句(带有嵌套的ifs等(。this 的每个分支都应该显式返回函数,或者调用某个-> !函数(例如process::exit(。

为了与其他程序员的沟通,以及为了保护自己免受自己的伤害,我想告诉编译器断言在此match之后的任何内容都是无法访问的。我知道它知道如何静态地执行此操作,因为如果我将代码放在那里,我会收到编译时警告。

我尝试过两件事:

  1. match语句分配给let _: ! = match ...。但是,!仍然是实验性的,所以这不起作用

  2. match包裹在闭合move || -> ! { match ... }();中。但是,这限制了我只能从父函数return


我的情况的具体细节不一定普遍适用:

  • 有问题的函数是fn main() -> ()
  • 条件逻辑必须发散到()返回函数,或者发散到!返回函数
  • 如果不这样做,则表示未正确处理或报告错误的路径
  • 条件逻辑中的return函数需要在那里使用由匹配项解开包装的值

这似乎只是一个问题,因为围绕单位类型的一些特殊怪癖()

  1. 当函数签名中省略返回类型时,()是默认值(因此fn main()等效于fn main() -> ()(;
  2. 即使您没有提供任何要返回的表达式,代码中的空块或语句也会计算为()

下面的示例之所以有效,是因为分号将表达式5转换为语句,因此丢弃其值。

fn foo() {
5;
}

递归地,当所有匹配组都没有产生其他类型的结果时,所有匹配组都很容易评估为()。使用return时就是这种情况,因为 return 语句会创建与执行流的真正背离:它的计算结果为 永不类型!,这会强制到任何其他类型。

fn foo(bar: i32) {
match bar {
1 => {
return do_good_things(); // coerces to () because of the default match arm
}
0 => {
return do_other_things(); // coerces to () because of the default match arm
}
_ => {
// arm evaluates to (), oops
}
}
}

这种单位类型的普遍存在通常有助于优雅的代码。但是,在这种情况下,当打算使用更严格的控制流时,它可能会触发误报。编译器无法解决此问题,除非我们引入另一种类型来解决这个问题

因此,这些解决方案是可能的:

  1. 为函数使用不同的返回类型。如果没有适用于返回的内容(例如,只有副作用(,你几乎可以使用任何类型,但另一个单位类型提供了更好的保证,它成为一个零成本的抽象。

操场

struct Check;
fn foo(bar: i32) -> Check {
match bar {
1 => {
do_good_things();
Check
}
0 => {
do_other_things();
return Check; // can use return
}
_ => {
// error[E0308]: expected struct Check, found ()
}
}
}
  1. 不要使用returnbreak语句,并确定所有匹配组都需要计算()以外的其他值。

操场

struct Check;
fn foo(bar: i32) {
let _: Check = match bar {
1 => {
do_good_things();
Check
}
0 => {
do_other_things();
Check
}
_ => {
// error[E0308]: expected struct Check, found ()
}
};
}
  1. 反之:确定匹配表达式的计算结果为零类型(类似于永不类型!(,以便除了使用控制流语句(如breakreturn(之外,任何匹配臂都无法从中返回。

操场

enum Nope {}
fn foo(bar: i32) {
let _: Nope = match bar {
1 => {
return do_good_things();
}
0 => {
return do_other_things();
}
_ => {
// error[E0308]: expected enum `Nope`, found ()
}
};
}

另请参阅:

  • 为什么 Rust 在 main 函数中没有返回值,无论如何如何返回值?

相关内容

最新更新