在Rust中编译时检查不可达

egdjgwm8  于 12个月前  发布在  其他
关注(0)|答案(1)|浏览(168)

我有一个由几个变量组成的枚举:

enum Foo {
  A,
  B,
  C,
}

字符串
我有一个函数,它有一个循环,里面有if和match,它的所有分支都是发散的:

fn my_function() -> i32 {
  // some vars
  for ... in ... { // also may be `while` or `loop`
    // some code
    if some_condition {
      let foo: Foo = ...;
      match foo {
        Foo::A => { return 42 }
        Foo::B => { continue }
        Foo::C => {
          // do something with vars
          continue
        }
      }
      // this place is currently unreachable
      // and must **always** be **totally** unreachable
      // because the code after `if` must never execute in this(`some_condition`) case
    }
    // some code
  }
}


但是随着未来的一些变化,我可能会添加新的变量到枚举中,所以我想在编译时检查该行是否不可访问。我觉得这应该是可能的,但我不知道如何做到这一点。
“现有技术”:

  • unreachable!对我不起作用,因为它是一个运行时检查,在这段代码执行之前需要很多时间,而且不能保证它会命中这个unreachable,因为在到达那里的过程中涉及到rng。
  • compile_error! made for cfg flags,在这种情况下,显然总是给出错误,而不依赖于该位置的可达性。
  • !-type -不确定是否可以使用never-type来解决这个问题。

如果存在像const_unreachable!soft_compile_error!这样的东西,当且仅当存在导致编译错误的执行路径时,它会填补这个确切的场景。
那么,这个问题有什么可能的解决方案(包括每晚生 rust 和任何功能)?

fwzugrvs

fwzugrvs1#

在nightly上,你可以将match的结果影响到一个“never”类型的变量:

#![feature(never_type)]

enum Foo {
  A,
  B,
}

fn main() {
    let x = Foo::A;
    let _: ! = match x {
        Foo::A => { println!("A"); return; }
        Foo::B => { println!("B"); /* Forgot `return` here */ }
    };
}

字符串
Playground
提供:

error[E0308]: mismatched types
  --> src/main.rs:12:19
   |
12 | Foo::B => { println!("B"); /* Forgot `return` here */ }
   |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `!`, found `()`
   |
   = note:   expected type `!`
           found unit type `()`


正如@rodrigo所指出的,在never类型稳定之前,可以使用std::convert::Infallible在稳定的Rust上实现同样的功能:

enum Foo {
  A,
  B,
}

fn main() {
    let x = Foo::A;
    let _: std::convert::Infallible = match x {
        Foo::A => { println!("A"); return; }
        Foo::B => { println!("B"); /* Forgot `return` here */ }
    };
}


Playground

相关问题