Rust 为什么联合体上的模式匹配会有无法访问的模式警告?

Rust 为什么联合体上的模式匹配会有无法访问的模式警告?,rust,pattern-matching,Rust,Pattern Matching,鉴于这种情况,我无法理解联合体上的模式匹配为何不能正常工作: 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"), } } 警告:无法访问的模式 -->src/main.r

鉴于这种情况,我无法理解联合体上的模式匹配为何不能正常工作:

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"),
    }
}

警告:无法访问的模式
-->src/main.rs:12:13
|
12 | A{a2}=>println!(“浮动”),
|             ^^^^^^^^
|
=注意:#[警告(无法访问的_模式)]默认打开
一个
联合体的全部要点是编译器不会在
联合体中存储任何关于它是什么类型的信息;这完全取决于程序员。因此,
匹配
没有用于确定值类型的信息

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

struct A {
    a1: i32,
}

let b = A { a1: 42 };

match b {
    A { a1 } => println!("int {}", a1),
    A { a1 } => println!("float {}", a1),
}
在任何情况下都不会执行第二个匹配臂

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

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

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

println!("{}", b);

如果希望编译器跟踪您的变量,您可能希望使用
enum
。在某些上下文中,枚举称为带标记的联合,因为它们正是这样的:一个联合,旁边有一个标记,用于标识该联合包含的内容

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

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),
    }
}
标记可以是您可以匹配的任何内容:

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),
    }
}
我想你甚至可以在工会周围使用枚举

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),
    }
}

谢谢你编辑我的问题!我不能改变工会。那么我可以使用
std::any::TypeId
吗?当然可以,但是假设union有很多字段,那么你的建议就不太可行了!也许可以存储
类型id
而不是
is\u int
并与之匹配?@EhsanM.Kermani如果你有一个有100种可能性的联盟,你会遇到更大的问题。不管怎样,我还是会说静态地强制执行更多的东西会更好。如果这不是您的目标,那么Rust可能不适合您或您试图解决的问题。@EhsanM.Kermani另外,如果您有一个具有相同类型的两种可能性的联合体,那么
TypeId
似乎将无法使用。