如何静态断言函数末尾无法到达

JMA*_*MAA 1 rust

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

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

我尝试过的两件事:

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

  2. 将其包裹match在封口中move || -> ! { match ... }();return但是,这限制了我只能从父函数中进行操作。


我的情况的具体细节不一定适用于一般情况:

  • 有问题的函数是fn main() -> ()
  • 条件逻辑必须要么分支到()返回函数,要么分支到!返回函数
  • 如果不这样做,则表明错误未正确处理或报告的路径
  • return条件逻辑中的 -ing 函数需要使用由匹配项展开的值

E_n*_*ate 5

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

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

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

fn foo() {
    5;
}
Run Code Online (Sandbox Code Playgroud)

()递归地,当所有匹配臂都没有产生另一种类型的结果时,很容易评估它们。使用时就是这种情况return,因为 return 语句与执行流产生了真正的分歧:它计算为 never 类型!,该类型强制为任何其他类型

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
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

这种单元类型的普遍存在通常有助于编写优雅的代码。然而,在这种情况下,当需要更严格的控制流程时,可能会触发误报。编译器无法解决这个问题,除非我们引入另一种类型来应对它

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

  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 ()
        }
    }
}
Run Code Online (Sandbox Code Playgroud)
  1. 不要使用returnorbreak语句,并确定所有匹配臂都需要评估为 以外的其他值()

操场

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 ()
        }
    };
}
Run Code Online (Sandbox Code Playgroud)
  1. 相反:确定匹配表达式的计算结果为零类型(类似于 never 类型!),以便除了使用控制流语句(例如breakor )之外,没有匹配臂可以从中返回return

操场

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 ()
        }
    };
}
Run Code Online (Sandbox Code Playgroud)

也可以看看: