如何为返回正确类型的枚举实现 get-method?

How do I implement a get-method for an enum that returns the right type?

提问人:exocortex 提问时间:2/1/2023 更新时间:2/1/2023 访问量:65

问:

我有一个枚举,其中包含包含某些类型的变体。我想编写一个方法,如果枚举变体包含此类型,则该方法会自动返回正确的类型。get

pub enum Var {
    Switch(bool),
    PositiveInteger(u32),
    Integer(i32),
    PositiveFloat(f64),
    Float(f64),
    Phase(f64), // a float x, where 0.0 <= x < 2Pi
    Turn(f64), // the same, but with 0.0 <= x < 1.0
}

在代码的其他地方,我想获取变体的内部,例如.但是(对我来说)似乎不可能编写一个泛型函数,如下所示:valuePositiveFloat( value )

impl Var {
    pub fn get<T>(&self) -> T 
where
    T: Default,
{
        match self {
            Var::Switch(value) => value,
            Var::PositiveInteger(value) => value,
            // etc
}

相反,我似乎必须为枚举的每个变体实现不同的 get-method:、 等。 也许我以错误的方式看待问题。我想实现这样的目标:get_positive_integer()get_integer()

let positive_integer = Var::PositiveInteger(1);
let x: u32 = positive_integer.get();

let float = Var::Float(0.1);
let y: f64 = float.get();
泛型 Rust 枚举

评论


答:

3赞 Chayim Friedman 2/1/2023 #1

您可以为此创建一个特征:

pub trait VarTypes: Sized {
    fn get(var: &Var) -> Option<Self>;
}

impl VarTypes for bool {
    fn get(var: &Var) -> Option<Self> {
        match *var {
            Var::Switch(v) => Some(v),
            _ => None,
        }
    }
}

impl VarTypes for u32 {
    fn get(var: &Var) -> Option<Self> {
        match *var {
            Var::PositiveInteger(v) => Some(v),
            _ => None,
        }
    }
}

impl VarTypes for i32 {
    fn get(var: &Var) -> Option<Self> {
        match *var {
            Var::Integer(v) => Some(v),
            _ => None,
        }
    }
}

impl VarTypes for f64 {
    fn get(var: &Var) -> Option<Self> {
        match *var {
            Var::PositiveFloat(v) | Var::Float(v) | Var::Phase(v) | Var::Turn(v) => Some(v),
            _ => None,
        }
    }
}

然后,你可以用它实现:get()

impl Var {
    pub fn get<T>(&self) -> T
    where
        T: VarTypes + Default,
    {
        T::get(self).unwrap_or_default()
    }
}

评论

0赞 exocortex 2/3/2023
谢谢!这很有帮助。我在这里没有想到特质。
3赞 cafce25 2/1/2023 #2

不能直接定义方法,因为每种类型都需要不同的实现。相反,您可以做的是定义一个通用特征,并为所需的每种类型实现该特征:impl Var

trait Get<T> {
    fn get(&self) -> Option<T>;
}

impl Get<bool> for Var {
    fn get(&self) -> Option<bool> {
        match self {
            Var::Switch(value) => Some(*value),
            _ => None,
        }
    }
}

impl Get<u32> for Var {
    fn get(&self) -> Option<u32> {
        match self {
            Var::PositiveInteger(v) => Some(*v),
            _ => None,
        }
    }
}

impl Get<f64> for Var {
    fn get(&self) -> Option<f64> {
        match self {
            Var::PositiveFloat(v) | Var::Float(v) | Var::Phase(v) | Var::Turn(v) => Some(*v),
            _ => None,
        }
    }
}
// …

我将返回类型更改为 因为它放宽了对的要求,并且更符合其他类似方法 (, ...) 并且您可以通过简单的语义重新获得语义:Option<T>Tslice::getunwrap_or_default()

let positive_integer = Var::PositiveInteger(1);
let x: u32 = positive_integer.get().unwrap_or_default();

评论

0赞 exocortex 2/3/2023
谢谢!我在这里和你一样使用它,效果非常好。还有错误处理。匪夷所思!