我应该使用枚举来模拟多态性还是使用Box <trait>中的trait?

Cha*_*Liu 6 polymorphism enums rust

使用enum Axes来限制CoordinateQuaternion

#[derive(Clone)]
pub enum Axes {
    Coordinate {x: f64, y: f64, z: f64, reserve: Vec<f64>,},
    Quaternion {x: f64, y: f64, z: f64},
}

impl Axes {
    pub fn shift(&mut self, Sample: &Axes) -> () {
        let Dup: Axes = self.clone();
        match Dup {
            Axes::Coordinate {x, y, z, reserve} => {
                match &Sample {
                    Axes::Coordinate {x, y, z, reserve} => {
                        *self = Axes::Coordinate {x: *x, y: *y, z: *z, reserve: reserve.to_vec()};
                    }
                    _ => panic!(),
                }
            }
            Axes::Quaternion {x, y, z} => {
                match &Sample {
                    Axes::Quaternion {x, y, z} => {
                        *self = Axes::Quaternion {x: *x, y: *y, z: *z};
                    }
                    _ => panic!(),
                }
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

使用特征Axes链接struct CoordinateQuaternion

pub trait Axes {
    fn shift(&mut self, Sample: &Axes) -> ();
    fn fold(&mut self, Sample: &Axes) -> ();
}

pub struct Coordinate {
    pub x: f64,
    pub y: f64,
    pub z: f64,
    pub reserve: Vec<f64>,
}

pub struct Quaternion {
    pub x: f64,
    pub y: f64,
    pub z: f64,
}

impl Axes for Coordinate {
    fn shift(&mut self, Sample: &Axes) -> () { }
    fn fold(&mut self, Sample: &Axes) -> () { }
}

impl Axes for Quaternion {
    fn shift(&mut self, Sample: &Axes) -> () { }
    fn fold(&mut self, Sample: &Axes) -> () { }
}
Run Code Online (Sandbox Code Playgroud)

struct在这种情况下,具有trait的特征是否更容易获得和更有效?我对在什么情况下使用哪个感到困惑。

Kwa*_*rtz 5

在根据情况使用特征和枚举之间的最大区别之一是它们的可扩展性。如果创建Axes枚举,则这两个选项将硬编码到类型中。如果要添加某种轴的第三种形式,则必须修改类型本身,这可能会涉及对带有用途的代码进行大量修改Axes(例如,Axes可能需要更改在a上匹配的任何位置)。另一方面,如果要制作Axes特征,则可以通过定义新类型并编写适当的实现方式来添加其他类型的轴,而无需完全修改现有代码。这甚至可以从库外部,例如由用户完成。

要考虑的另一重要事项是您需要对结构的内部进行多少访问。使用枚举,您可以完全访问结构中存储的所有数据。如果你想要写一个可以同时操作的功能CoordinateQuaternion使用特点,那么你将是唯一的操作能够执行是那些所描述的Axes特征(在这种情况下,ShiftFold)。例如,给出Axes您所给出的实现,就没有办法让您简单地(X,Y,Z)通过Axes接口检索元组。如果需要在某个时候这样做,则必须添加一个新方法。

在不了解更多有关如何计划使用这些类型的信息的情况下,很难确定其中哪个选项是更好的选择,但是如果是我,我可能会使用一个枚举。最终,它很大程度上取决于偏好,但是希望这可以使您对做出决定时要考虑的事情有所了解。


mca*_*ton 5

@Kwarrtz的答案中未提及的另一个差异是与内存相关的。

  • enums可以直接存储在堆栈上,而装箱的特征始终需要堆。也就是说,enum创建s很便宜,但装箱的特征却不是。
  • enum即使您主要存储小变体,一个实例也总是与其最大变体一样大(在大多数情况下还要加上判别式)。在这种情况下,这将是一个问题:

    enum Foo {
        SmallVariant(bool),
        BigVariant([u64; 100]),
    }
    
    Run Code Online (Sandbox Code Playgroud)

    如果要在向量中存储N个这种类型的实例N*(100*sizeof::<u64> + sizeOfDiscriminant),则即使向量仅包含SmallVariants ,向量也总是需要字节的内存。

    如果您使用的是盒装特征,则矢量将使用N * sizeOfFatPointer == N * 2 * sizeof::<usize>

  • 仅出于完整性考虑,如果仅在BigVariant内对数组进行装箱,则向量的最终大小与装箱的特征版本相同,但是除了堆栈分配之外,您还可以获得enum的其他优点。 (2认同)