当前位置: 首页 > 知识库问答 >
问题:

生锈匹配:简单枚举上的“虚假”非穷举错误:如何“传播”枚举变量种类知识?

景英杰
2023-03-14

我打了一个有趣的虚假的“匹配中匹配”非详尽的铁锈错误。做一个简单的小例子(当然生产案例更有趣):

pub enum SomeEnum {
    Possibility1,
    Possibility2,
    Possibility3
}

pub fn do_something(some: &SomeEnum){
    match some {
        SomeEnum::Possibility1 => println!("this is possibility 1"),
        something_else => {
            println!("this is not possibility 1");

            match something_else {
                SomeEnum::Possibility2 => println!("but this is 2"),
                SomeEnum::Possibility3 => println!("but this is 3")
            }
        }
    }
}

未编译,但出现错误:

error[E0004]: non-exhaustive patterns: `&Possibility1` not covered
  --> src/main.rs:13:19
   |
1  | / pub enum SomeEnum {
2  | |     Possibility1,
   | |     ------------ not covered
3  | |     Possibility2,
4  | |     Possibility3
5  | | }
   | |_- `SomeEnum` defined here
...
13 |               match something_else {
   |                     ^^^^^^^^^^^^^^ pattern `&Possibility1` not covered
   |
   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
   = note: the matched value is of type `&SomeEnum`

我理解这个错误,我知道如何“残酷地”修复它(类似于非详尽模式——通过添加一个生锈匹配表达式:

_ => unreachable!();

例如分支机构)。

尽管如此,我还是觉得这很可悲:编译器在第一次匹配时足够聪明,知道其他东西是某种可能性2可能性3,而把这些知识扔掉?

因此,我的问题是:有没有一种简单、惯用的方法来迫使锈蚀将这种知识从外部匹配“传播”到内部匹配,这样我就可以在不残酷匹配所有输入的情况下抑制错误?同样,在这个简单的例子中,_匹配似乎是显而易见的,但是在一些更复杂的代码中,我希望编译器帮助检查我的逻辑是否正确,这就取消了使用<_匹配过滤器。

共有1个答案

堵睿范
2023-03-14

尽管如此,我还是觉得这很悲哀:编译器在第一次匹配时足够聪明,知道其他东西可能是2或3

不是,真的。从语义上来说,它只是一个接一个地尝试每一个匹配的手臂,然后拿走第一个。

因此,我的问题是:有没有一种简单、惯用的方法来迫使锈菌将这种知识从外部匹配“传播”到内部匹配

不。就类型级别而言,rustc的原因(主要是)someone是一个SomeEnum,而SomeEnum有一个SomeEnum::posability1。如果你想要一个子枚举,你必须提供一个。

如果RFC2593枚举变量类型(或类似于OCaml样式多态变量的替代类型)再次被提交、接受和实现,这种事情最终可能是可行的。但除此之外,您必须在enum上“手动”实现它。

我所说的“手工完成”是指手动将你想要的语义编码为额外的枚举。

pub enum SomeEnum {
    Possibility1,
    Possibility2,
    Possibility3
}

enum IsOne { One, Other(Sub23) }
enum Sub23 {
    Sub2,
    Sub3
}
impl SomeEnum {
    fn is_one(&self) -> IsOne {
        match self {
            Self::Possibility1 => IsOne::One,
            Self::Possibility2 => IsOne::Other(Sub23::Sub2),
            Self::Possibility3 => IsOne::Other(Sub23::Sub3),
        }
    }
}

pub fn do_something(some: &SomeEnum){
    match some.is_one() {
        IsOne::One => println!("this is possibility 1"),
        IsOne::Other(sub) => {
            println!("this is not possibility 1");

            match sub {
                Sub23::Sub2 => println!("but this is 2"),
                Sub23::Sub3 => println!("but this is 3")
            }
        }
    }
}
 类似资料:
  • 问题内容: 例如,我该怎么做: 结果示例: 问题答案: 迅捷4.2+ 从Swift 4.2(使用Xcode 10)开始,只需添加协议一致性即可从中受益。要添加此协议一致性,您只需要在某处写: 如果枚举是您自己的,则可以直接在声明中指定一致性: 然后,以下代码将打印所有可能的值: 与早期Swift版本(3.x和4.x)的兼容性 如果您需要支持Swift 3.x或4.0,则可以通过添加以下代码来模仿S

  • 让我们看看一个需要诉诸于代码的场景,来考虑为何此时使用枚举更为合适且实用。假设我们要处理 IP 地址。目前被广泛使用的两个主要 IP 标准:IPv4(version four)和 IPv6(version six)。这是我们的程序可能会遇到的所有可能的 IP 地址类型:所以可以 枚举 出所有可能的值,这也正是此枚举名字的由来。 任何一个 IP 地址要么是 IPv4 的要么是 IPv6 的,而且不能

  • 问题内容: 这不是卡住我的问题,而是我正在寻找一种编写代码的整洁方法。 本质上,我正在编写一个事件驱动的应用程序。用户触发一个事件,该事件被发送到适当的对象,然后这些对象处理事件。现在,我正在编写偶数处理程序方法,并且希望使用switch语句确定如何处理事件。现在,在我研究通用结构时,事件类非常简单: 然后,在另一堂课中,我会看到类似以下内容的内容: 我会 喜欢 做的就是这样的事情(尽管我当然会坚

  • 例如,我如何做类似的事情: 结果示例:

  • 问题内容: Java中的静态和非静态枚举有什么区别?两种用法是相同的。 正确吗 所有静态的都在启动时加载到内存中,非静态的则按需加载 ? 如果是,那么哪种方法更好?将某些数据始终保留在内存中还是每次使用服务器资源加载它们? 问题答案: 所有的都是有效的。如果您有嵌套的枚举,则它与相同。 所有类都是延迟加载的(枚举或其他),但是在加载时,它们会一次全部加载。也就是说,您不能加载一些常量,而不能加载其

  • 当您需要定义错误码和错误信息时,可能会使用以下方式, <?php class ErrorCode { const SERVER_ERROR = 500; const PARAMS_INVALID = 1000; public static $messages = [ self::SERVER_ERROR => 'Server Error',