将 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);
}
当 运行在 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,
}
我发现我可以将 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);
}
当 运行在 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,
}