假设我有以下枚举 - 混合 c 风格赋值和变体枚举:
enum Command {
Control(ControlSubcommand) = 0x00,
Temperature = 0x02,
Voltage = 0x04,
...
}
enum ControlSubcommand {
Status = 0x00,
DeviceType = 0x01,
....
}
然后,当我尝试将给定命令解构为单个值时,我将其传递给函数。对于直接分配值(温度、电压等)的 C 风格命令,我想获取它的相应值 - 所以 0x02、0x04 等等。
对于“变体”命令(控制),我想获取它的值和子命令 - 所以 0x00 与 0x00、0x01 等等。
我正在尝试编写以下匹配结构来执行此操作:
match command {
Command::Control(subcommand) => {
println!("control command with subcommand {}", subcommand as u32);
}
simple => {
println!("simple command {}", simple as u32);
}
}
但问题是,从技术上讲,
simple
仍然是Command
,它是非原始类型,因此as
强制转换不适用于它。即使变体案例之前已经处理过并且不会出现在 simple
中,Rust 仍然不允许我执行强制转换。
是否可以在不更改枚举布局的情况下以某种方式修复此代码?
as
演员阵容不起作用如果您不想一一匹配变体,而是希望尽快回退到判别式的数值,则可以在
unsafe
的帮助下实现(是的,它很难看)。
Discriminant
返回的 std::mem::discriminant()
的数值。
由于我们用 #[repr(u32)]
指定判别式的形状,因此我们可以假设应用 std::mem::transmute()
运算以获得底层 u32
。
#[repr(u32)]
enum Command {
Control(ControlSubcommand) = 0x00,
Temperature = 0x02,
Voltage = 0x04,
//...
}
#[repr(u32)]
enum ControlSubcommand {
Status = 0x00,
DeviceType = 0x01,
//....
}
fn main() {
let cmds = [
Command::Control(ControlSubcommand::Status),
Command::Control(ControlSubcommand::DeviceType),
Command::Temperature,
Command::Voltage,
];
for command in cmds {
let d1: u32 =
unsafe { std::mem::transmute(std::mem::discriminant(&command)) };
match command {
Command::Control(subcommand) => {
let d2 = subcommand as u32;
println!("control command ({}) with subcommand {}", d1, d2);
}
_ => {
println!("simple command {:?}", d1);
}
}
}
}
/*
control command (0) with subcommand 0
control command (0) with subcommand 1
simple command 2
simple command 4
*/