为什么联合上的模式匹配会出现无法访问的模式警告? [英] Why does pattern matching on a union have an unreachable pattern warning?

查看:47
本文介绍了为什么联合上的模式匹配会出现无法访问的模式警告?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

鉴于 文档,我不明白为什么联合上的模式匹配无法正常工作:

Given the documentation, I cannot understand why the pattern matching on a union doesn't work properly:

union A {
    a1: i32,
    a2: f32,
}

struct B(A);
let b = B(A { a2: 1.0 });
unsafe {
    match b.0 {
        A { a1 } => println!("int"),
        A { a2 } => println!("float"),
    }
}

输出int"无法访问警告.

warning: unreachable pattern
  --> src/main.rs:12:13
   |
12 |             A { a2 } => println!("float"),
   |             ^^^^^^^^
   |
   = note: #[warn(unreachable_patterns)] on by default

推荐答案

union全部点是编译器不会在 union 中存储任何信息code>union 关于它是什么类型;这完全取决于程序员.因此,match 没有信息可用于确定值的类型.

The entire point of a union is that the compiler doesn't store any information in the union about what type it is; it's completely up to the programmer. Because of this, there's no information for a match to use to decide what type the value is.

因此,您的代码在概念上等同于

Because of this, your code is conceptually equivalent to

struct A {
    a1: i32,
}

let b = A { a1: 42 };

match b {
    A { a1 } => println!("int {}", a1),
    A { a1 } => println!("float {}", a1),
}

不会在任何情况下执行第二个匹配分支.

There's no case in which the second match arm will ever be executed.

事实上,在字段之间来回切换是联合的主要用法:

In fact, switching back and forth between the fields is a prime usage of a union:

union A {
    i: i32,
    f: f32,
}

let a = A { i: 42 };
let b = unsafe { a.f };

println!("{}", b);

<小时>

如果您希望编译器跟踪您拥有的变体,您可能希望使用 enum.在某些情况下,枚举被称为标记联合,因为这正是它们的本质:一个带有标记的联合,用于标识联合包含的内容.


You may wish to use an enum if you want the compiler to keep track of what variant you have. In some contexts, enums are called tagged unions because that's exactly what they are: a union with a tag alongside to identify what the union contains.

否则,您需要以其他方式跟踪联合中实际存在的类型.其中一种方法是实现您自己的标签:

Otherwise, you need to track what type is actually in the union in some other manner. One such way is to implement your own tag:

union A {
    a1: i32,
    a2: f32,
}

struct B {
    is_int: bool,
    data: A,
}

let b = B {
    is_int: false,
    data: A { a2: 1.0 },
};

unsafe {
    match b {
        B {
            is_int: true,
            data: A { a1 },
        } => println!("int {}", a1),
        B {
            is_int: false,
            data: A { a2 },
        } => println!("float {}", a2),
    }
}

标签可以是您可以匹配的任何内容:

The tag can be anything you can match on:

union A {
    a1: i32,
    a2: f32,
}

struct B {
    kind: Kind,
    data: A,
}

enum Kind {
    Int,
    Float,
}

let b = B {
    kind: Kind::Float,
    data: A { a2: 1.0 },
};

unsafe {
    match b {
        B {
            kind: Kind::Int,
            data: A { a1 },
        } => println!("int {}", a1),
        B {
            kind: Kind::Float,
            data: A { a2 },
        } => println!("float {}", a2),
    }
}

我想你甚至可以在联合周围使用枚举......

I suppose you could even use an enum around the union...

union A {
    a1: i32,
    a2: f32,
}

enum B {
    Int(A),
    Float(A),
}

let b = B::Float(A { a2: 1.0 });

unsafe {
    match b {
        B::Int(A { a1 }) => println!("int {}", a1),
        B::Float(A { a2 }) => println!("float {}", a2),
    }
}

这篇关于为什么联合上的模式匹配会出现无法访问的模式警告?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆