Given the documentation,我不明白为何联合上的模式匹配无法正常工作:
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
答案 0 :(得分:5)
union
的 entire 点是,编译器没有在union
中存储有关其类型的任何信息。 完全取决于程序员。因此,match
没有信息可用于确定该值是什么类型。
因此,您的代码在概念上等同于
struct A {
a1: i32,
}
let b = A { a1: 42 };
match b {
A { a1 } => println!("int {}", a1),
A { a1 } => println!("float {}", a1),
}
在任何情况下都不会执行第二个比赛臂。
实际上,在字段之间来回切换是union
的主要用法:
union A {
i: i32,
f: f32,
}
let a = A { i: 42 };
let b = unsafe { a.f };
println!("{}", b);
如果希望编译器跟踪所拥有的变体,则可能希望使用enum
。在某些情况下,枚举被称为 tagged联合,因为这正是它们的本质:一个带有标签的联合,以标识该联合包含的内容。
否则,您需要以其他方式跟踪联合中实际上是什么类型。一种方法是实现自己的标签:
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),
}
}