【问题标题】:Rust - Get Enum-With-Data OrdinalRust - 获取带数据的枚举序数
【发布时间】:2023-01-17 04:32:07
【问题描述】:

我正在尝试序列化一个枚举。我计划通过首先对枚举的序数进行编码,然后对与 enum to bytes / bytes to enum? 非常相似的值进行序列化。这个问题的答案涉及使用一个板条箱,serde;我想避免使用这个板条箱。

似乎有两种类型的枚举:有数据和没有数据,它们在某些方面是不兼容的。使用 as u8 似乎可以从没有数据的枚举中获取序数值,非常简单。一个值从 as u8 返回带有数据的枚举变体,但是没有数据的枚举变体(当其他枚举变体有数据时)无法编译:

https://play.rust-lang.org/?gist=2f6a4e8507a59d451546a69407bc0d77

#[repr(u8)]
enum Enumeration {
    One=0,
}

#[repr(u8)]
enum Other {
    Twelve(String)=4,
    Thirteen=5,
}
fn main() {
    println!("Got unsigned {:?}", Enumeration::One as u8);
    println!("Got other {:?}", Other::Twelve as u8);
    // Uncommenting the next line produces a compiler error
    //println!("Got other {:?}", Other::Thirteen as u8);
}

(我的印象是从带有数据的枚举变体返回的值没有用。)

如何获取带有数据的枚举变体的序数?

【问题讨论】:

  • 你没有得到 Twelve 的判别式。
  • @ChayimFriedman 没错。在阅读“鉴于 rustc 保证 #[repr(u16)] 枚举以其判别式存储为 u16...”(github.com/rust-lang/rfcs/pull/2363/files)开始后,我感到有些惊讶。

标签: rust enums


【解决方案1】:

TLDR;您正在将函数指针转换为 u8,而不是您想要的。如果你愿意,可以使用serde 或类似的方式来实现你的目标。


所以,在你的代码上运行 clippy 可以很好地说明这里发生了什么:

warning: casting function pointer `Other::Twelve` to `u8`, which truncates the value
  --> src/main.rs:13:32
   |
13 |     println!("Got other {:?}", Other::Twelve as u8);
   |                                ^^^^^^^^^^^^^^^^^^^ help: try: `Other::Twelve as usize`
   |
   = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#fn_to_numeric_cast_with_truncation
   = note: `#[warn(clippy::fn_to_numeric_cast_with_truncation)]` on by default

warning: cast of an enum tuple constructor to an integer
  --> src/main.rs:13:32
   |
13 |     println!("Got other {:?}", Other::Twelve as u8);
   |                                ^^^^^^^^^^^^^^^^^^^
   |
   = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#cast_enum_constructor
   = note: `#[warn(clippy::cast_enum_constructor)]` on by default

所以,这可能不是你想要的。

如果我们深入挖掘 nomicon,我们可以找到this article

如果枚举有字段,效果类似于 repr(C) 的效果,因为有定义的类型布局。这使得将枚举传递给 C 代码或访问类型的原始表示并直接操作其标记和字段成为可能。有关详细信息,请参阅 RFC。

[...]

将显式 repr(u*)、repr(i*) 或 repr(C) 添加到具有字段的枚举会抑制空指针优化,例如:

enum MyOption<T> {
    Some(T),
    None,
}

#[repr(u8)]
enum MyReprOption<T> {
    Some(T),
    None,
}

assert_eq!(8, size_of::<MyOption<&u16>>());
assert_eq!(16, size_of::<MyReprOption<&u16>>());

如果你想阅读你可以用它做什么,请遵循 RFC:https://github.com/rust-lang/rfcs/blob/master/text/2195-really-tagged-unions.md#guide-level-explanation

【讨论】:

    【解决方案2】:

    基于

    鉴于 rustc 保证 #[repr(u16)] 枚举以其存储为 u16 的判别式开始......

    这里:https://github.com/rust-lang/rfcs/pull/2363/files,枚举值的第一个字节应该是底层的u8。所以...

    https://play.rust-lang.org/?gist=21e3ab42f76ccbc05b6b61560cbd29ec

    #[repr(u8)]
    enum MyOption {
        Option(String),
        NotOption,
    }
    
    fn get_ordinal(option: MyOption) -> u8 {
        let ptr_to_option = (&option as *const MyOption) as *const u8;
        unsafe {
            *ptr_to_option
        }
    }
    
    fn main() {
        let option = MyOption::Option("Yolo".to_string());
        let not_option = MyOption::NotOption;
        println!("ordinal for Option is {}; NotOption is {}", 
            get_ordinal(option), get_ordinal(not_option));
    }
    

    输出ordinal for Option is 0; NotOption is 1

    【讨论】:

      猜你喜欢
      • 2022-08-18
      • 2021-08-15
      • 1970-01-01
      • 2015-01-12
      • 1970-01-01
      • 1970-01-01
      • 2010-11-30
      • 1970-01-01
      • 2014-07-26
      相关资源
      最近更新 更多