Function std::mem::discriminant

1.21.0 (const: unstable) · source ·
pub fn discriminant<T>(v: &T) -> Discriminant<T>
Expand description

返回一个唯一标识 v 中的枚举变体的值。

如果 T 不是枚举,则调用此函数不会导致未定义的行为,但返回值是未指定的。

Stability

如果枚举定义改变,则枚举变体的判别式可能会改变。某些变体的判别式在使用相同编译器的编译之间不会改变。 有关更多信息,请参见 Reference

Examples

这可以用来比较携带数据的枚举,而忽略实际数据:

use std::mem;

enum Foo { A(&'static str), B(i32), C(i32) }

assert_eq!(mem::discriminant(&Foo::A("bar")), mem::discriminant(&Foo::A("baz")));
assert_eq!(mem::discriminant(&Foo::B(1)), mem::discriminant(&Foo::B(2)));
assert_ne!(mem::discriminant(&Foo::B(3)), mem::discriminant(&Foo::C(3)));
Run

访问判别式的数值

请注意,从 Discriminant 到原语,到 transmute未定义的行为!

如果枚举只有元变体,则可以使用 as 转换访问判别式的数值:

enum Enum {
    Foo,
    Bar,
    Baz,
}

assert_eq!(0, Enum::Foo as isize);
assert_eq!(1, Enum::Bar as isize);
assert_eq!(2, Enum::Baz as isize);
Run

如果枚举已选择使用 primitive representation 作为它的判别式,则可以使用指针读取存储判别式的内存位置。 然而,对于使用 default representation 的枚举,不能这样做,因为它没有定义判别式的布局和存储位置 – 它甚至可能根本不存储!

#[repr(u8)]
enum Enum {
    Unit,
    Tuple(bool),
    Struct { a: bool },
}

impl Enum {
    fn discriminant(&self) -> u8 {
        // SAFETY: 因为 `Self` 被标记为 `repr(u8)`,它的布局是 `repr(C)` 结构体之间的一个 `repr(C)` `union`,每个 `u8` 的判别式作为它的第一个字段,所以我们可以在不偏移指针的情况下读取判别式。
        unsafe { *<*const _>::from(self).cast::<u8>() }
    }
}

let unit_like = Enum::Unit;
let tuple_like = Enum::Tuple(true);
let struct_like = Enum::Struct { a: false };
assert_eq!(0, unit_like.discriminant());
assert_eq!(1, tuple_like.discriminant());
assert_eq!(2, struct_like.discriminant());

// ⚠️ 这是未定义的行为。不要这样做。⚠️
// assert_eq!(0, unsafe { std::mem::transmute::<_, u8>(std::mem::discriminant(&unit_like)) });
Run