是否可以有一个结构,其中字段是枚举中的一个项目?锈

Is it possible to have a struct where the field is an item from an enum? Rust

是否可以有一个通用结构,使得结构中的项目是来自枚举的项目?例如:

enum AcceptableDataType {
    String(String),
    U8(u8),
}

struct Data<K, V> 
where 
    K: AcceptableDataType,
    V: AcceptableDataType,
{
    map: HashMap<K, V>,
}

或者这是应该由特征处理的东西?我只是不确定如何以生锈的方式处理这种情况。

没有。有一个 RFC,Types for enum variants, but it was postponed:

While we may want to do something along these lines eventually, given the roadmap I think there is more pressing work on the language side, and this RFC has stalled.

惯用的方法就是使用负载类型(您可能需要为它创建一个结构)。喜欢:

struct Data<K, V>  {
    map: HashMap<K, V>,
}

Data<String, u8>

您可以使用特征来构建枚举,例如:

trait Enum<Variant>: Sized {
    fn from_variant(v: Variant) -> Self;
    fn into_variant(self) -> Option<Variant>;
    fn as_variant(&self) -> Option<&Variant>;
    fn as_variant_mut(&mut self) -> Option<&mut Variant>;
}

impl Enum<String> for AcceptableDataType {
    fn from_variant(v: String) -> Self { Self::String(v) }
    fn into_variant(self) -> Option<String> {
        match self {
            Self::String(v) => Some(v),
            _ => None,
        }
    }
    fn as_variant(&self) -> Option<&String> {
        match self {
            Self::String(v) => Some(v),
            _ => None,
        }
    }
    fn as_variant_mut(&mut self) -> Option<&mut String> {
        match self {
            Self::String(v) => Some(v),
            _ => None,
        }
    }
}
impl Enum<u8> for AcceptableDataType {
    fn from_variant(v: u8) -> Self { Self::U8(v) }
    fn into_variant(self) -> Option<u8> {
        match self {
            Self::U8(v) => Some(v),
            _ => None,
        }
    }
    fn as_variant(&self) -> Option<&u8> {
        match self {
            Self::U8(v) => Some(v),
            _ => None,
        }
    }
    fn as_variant_mut(&mut self) -> Option<&mut u8> {
        match self {
            Self::U8(v) => Some(v),
            _ => None,
        }
    }
}

struct Data<E, K, V>
where
    E: Enum<K>,
    E: Enum<V>,
{
    map: HashMap<K, V>,
}
// etc.

请注意,此特性并不完美:如果两个变体具有相同的有效负载类型,则它不起作用。您也可以改进它以在这种情况下工作,还可以创建一个 proc 宏来轻松派生它。

如果我对你的问题的理解正确,你应该通过创建一个在 Stringu8.

上实现的特征来实现它。
trait AcceptableDataType {}

impl AcceptableDataType for String {}

impl AcceptableDataType for u8 {}

struct Data<K, V> 
where 
    K: AcceptableDataType,
    V: AcceptableDataType,
{
    map: HashMap<K, V>,
}

请注意,在 Data 中,您不能只“检查”它是哪种类型,您只知道它是一个 AcceptableDataType,它不会给您任何信息。

如果你需要取回两者的枚举,我会在特征中包含一个方法来这样做:

enum AcceptableDataTypeEnum {
    String(String),
    U8(u8),
}

trait AcceptableDataType {
    fn into_enum(self) -> AcceptableDataTypeEnum;
}

并在 impls 中实现功能。

如果你不希望任何下游用户能够向特征添加新项目,你也可以sealed

如果你有一组复杂的 impl,可能涉及重叠的泛型,但你只想将特征用作“标记”,那么你也可以使用不稳定的 night-only 特性 marker-trait-attr.

但是请注意,这会阻止您在特征上使用方法,因此您不能使用上述方法取回枚举,您需要为此专门化,这是一个不完整的功能。