Rust中如何获取带数据枚举(Enum-With-Data)的序号值?
在不使用serde的情况下获取混合枚举变体的序号值
当枚举同时包含带数据和不带数据的变体时,as u8的转换方式会失效,你可以通过以下几种方式获取每个变体的序号值:
方法1:手动实现匹配函数
这是最直观且可控的方式,为枚举编写一个方法,通过模式匹配返回对应变体的序号:
#[repr(u8)] enum Other { Twelve(String) = 4, Thirteen = 5, } impl Other { fn discriminant(&self) -> u8 { match self { Other::Twelve(_) => 4, Other::Thirteen => 5, } } } fn main() { let var1 = Other::Twelve("test".to_string()); let var2 = Other::Thirteen; println!("Twelve的序号: {}", var1.discriminant()); // 输出4 println!("Thirteen的序号: {}", var2.discriminant()); // 输出5 }
适合变体数量不多的场景,无需依赖外部库,逻辑清晰不易出错。
方法2:用宏自动生成获取逻辑
如果枚举变体较多,手动写匹配易重复出错,可以用Rust宏自动生成序号读取方法:
#[repr(u8)] enum Other { Twelve(String) = 4, Thirteen = 5, } macro_rules! discriminant { ($enum_type:ty, $($variant:ident $(($arg:ty))* = $disc:expr),*) => { impl $enum_type { fn discriminant(&self) -> u8 { match self { $( $enum_type::$variant $((_))* => $disc, )* } } } }; } // 为Other枚举生成discriminant方法 discriminant!(Other, Twelve(String)=4, Thirteen=5); fn main() { let var1 = Other::Twelve("test".to_string()); let var2 = Other::Thirteen; println!("Twelve的序号: {}", var1.discriminant()); println!("Thirteen的序号: {}", var2.discriminant()); }
宏会根据你定义的变体和对应序号自动生成匹配逻辑,减少重复代码量。
方法3:unsafe读取内存中的判别式
借助#[repr(u8)]的内存布局保证,可通过unsafe代码直接读取枚举实例的判别式字节。但这种方式依赖Rust内存实现细节,需谨慎使用:
#[repr(u8)] enum Other { Twelve(String) = 4, Thirteen = 5, } impl Other { unsafe fn discriminant(&self) -> u8 { // 读取枚举实例的第一个字节(#[repr(u8)]下判别式存储在首字节) *(self as *const Self as *const u8) } } fn main() { let var1 = Other::Twelve("test".to_string()); let var2 = Other::Thirteen; unsafe { println!("Twelve的序号: {}", var1.discriminant()); println!("Thirteen的序号: {}", var2.discriminant()); } }
⚠️ 注意:若后续修改枚举的repr属性、变体顺序或定义,可能引发未定义行为,仅在必要场景使用。
内容的提问来源于stack exchange,提问作者lmat - Reinstate Monica
相关产品推荐
相关产品推荐

