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"),
}
}
Outputs "int" with an unreachable warning.
warning: unreachable pattern
--> src/main.rs:12:13
|
12 | A { a2 } => println!("float"),
| ^^^^^^^^
|
= note: #[warn(unreachable_patterns)] on by default
The entire point of a
union
is that the compiler doesn't store any information in theunion
about what type it is; it's completely up to the programmer. Because of this, there's no information for amatch
to use to decide what type the value is.Because of this, your code is conceptually equivalent to
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
: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:
The tag can be anything you can match on:
I suppose you could even use an enum around the union...