将 Rust 枚举变体转换为数字数据类型的含义是什么?

What's the meaning of casting a Rust enum variant to a numeric data type?

我发现我可以将 Enum 变体转换为数字类型,但是,并不是 100% 清楚 meaning/usefulness 是什么,特别是因为语义会根据特定条件而变化。

基本形式:

enum Simple {
    A,
    B,
}

println!("{}", Simple::A as u8);   // 0
println!("{:?}", Simple::B as u8); // 1

具有从 0 开始的无符号正数的数值(至少,对于这种特定情况)

但是,嵌入的变体令人困惑:

enum WithEmbed {
    A(String),
    B,
}

println!("{}", WithEmbed::A as u8);            // 48!?
println!("{}", WithEmbed::A("".into()) as u8); // error!?
println!("{}", WithEmbed::B as u8);            // error!?

带有嵌入的枚举变体的数字转换是什么意思?

将非 C 类型的枚举(因此,带有字段的枚举,就像在您的第二个示例中一样)转换为整数是不可能的。这就是第二个示例中的转换失败的原因。

但是,为什么这个转换有效?

println!("{}", WithEmbed::A as u8);            // 48!?

不是转换枚举,而是将枚举构造函数转换为包含函数地址的整数。您可以将任何函数转换为包含其地址的整数:

fn main() {
    enum WithEmbed {
        A(String),
        B,
    }
    
    println!("0x{:x}", WithEmbed::A as usize);
    println!("0x{:x}", main as usize);
}

Playground

当 运行在 Rust 操场上执行此操作时,我得到:

WithEmbed:A: 0x563813475b70
main:        0x563813475a50

如果您 运行 在您自己的机器上,您可能会得到一些稍微不同的东西,但如您所见,这只是转换函数指针。还有 an issue on Github 描述了这种行为。


此外,为了完整起见:

The basic form [...] has a numeric value of an unsigned positive number starting from 0 (at least, for this specific case)

的确如此,仅在这种特定情况下。 Rust 编译器可以自由地分配其他整数或做任何它想做的事情(甚至根本不分配任何整数——例如,一个 Option<&T> 只存储一个原始指针,如果这个指针为 NULL,选项等于 None。这被称为 Rust 的空指针优化,请参阅结尾附近的 here)。

如果您依赖于具有从 0 开始递增的值的枚举,您可以显式地分配它们...

enum Simple {
    A = 0,
    B = 1,
}

...或将表示设置为 C 或整数类型:

// With regards to the value describing enum variant, all three are equivalent
#[repr(C)]
enum SimpleC {
    A,
    B,
}

#[repr(u8)]
enum SimpleU8 {
    A,
    B,
}

#[repr(i8)]
enum SimpleI8 {
    A,
    B,
}

Playground