如何克隆具有关联类型的特征的Box的Vec

时间:2019-06-19 12:28:57

标签: rust traits

我有一个枚举。因为我希望枚举稍后包含数十个条目并进行多重分类,并且大多数相关处理将基于其所属的类别而不是枚举变体本身进行,所以我现在考虑切换到具有关联类型的特征(类别) 。 这样可以避免多个函数具有相同的匹配臂,我发现它们容易出错,尤其是因为它们会分散在整个代码中。

我设法获得了一些我喜欢的自动实现的功能(当使用宏时),这些代码在枚举情况下是不可能的:

  • 每个struct(以前是变体)只能具有一个类别(每个类别类型),并且对于该struct的所有值都是强制一致的
  • 我可以推送将要分发的所有不同类型的结构,并以每个类别的Vec结尾。

与类别相关的代码(实际上是此MWE除外)将通过使用宏生成。但是,我找不到克隆Categorized结构的方法。

trait Foo//: Clone Uncommenting breaks compilation because of object-safety
{
    type Category: Category;
}

trait Category {}

struct A;
impl Category for A {}
// ... structs and impls like the above

#[derive(Clone, Copy)]
struct Bar;
impl Foo for Bar {
    type Category = A;
}

//#[derive(Clone)] Uncommenting breaks compilation because Foo is not Clone
struct Categorized {
    cat_a: Vec<Box<dyn Foo<Category = A>>>,
    //cat_b: Vec<Box<dyn Foo<Category = B>>>,
}

trait Pushable<T, C>
where
    T: Foo<Category = C>
{
    fn push(&mut self, rend: T);
}

impl<T: 'static> Pushable<T, A> for Categorized
where
    T: Foo<Category = A>
{
    fn push(&mut self, v: T) {
        self.cat_a.push(Box::new(v));
    }
}

fn main() {
    let mut cats = Categorized { cat_a: vec![] };
    cats.push(Bar{});
    let mut cat_a: Vec<Box<dyn Foo<Category = A>>> = Vec::new();
    cat_a.push(Box::new(Bar{}));
    //cat_a.clone(); Uncommenting breaks compilation because Foo is not Clone
}

我为“您必须使用枚举”感到讨厌,但是,我该如何解决呢?

编辑:尽管与建议的问题非常相似,但我无法使用该方法解决问题。为此,我必须使trait Foo通用而不是具有关联的类型,因为克隆间接性状要么是通用的,要么具有关联的类型:

trait Foo<C>: FooBoxClone<C>
where
    C: Category,
{
    type Category;
}

trait FooBoxClone<C> {
    fn clone_box(&self) -> Box<dyn Foo<C, Category = C>>;
}

impl<C, T> FooBoxClone<C> for T
where
    T: 'static + Foo<C, Category = C> + Clone,
    C: Category,
{
    fn clone_box(&self) -> Box<dyn Foo<C, Category = C>> {
        Box::new(self.clone())
    }
}

impl<C: Category> Clone for Box<dyn Foo<C, Category = C>> {
    fn clone(&self) -> Self {
        FooBoxClone::clone_box(&**self)
    }
}

除了编写Foo<C, Category = C>的笨拙之外,我还能做到:

struct B;
impl Category for B {}
impl Foo<B> for Bar {
    type Category = B;
}

这意味着Bar将属于多个类别(并且为Pushable实现了正确的B之后,cats.push(Bar{});需要类型注释)

相反,我还可以尝试为所有可能的Category做一个间接特征,但是那样我会遇到另一组问题:

trait Foo {
    type Category;
}

pub trait FooABoxClone {
    fn clone_box(&self) -> Box<dyn Foo<Category = A>>;
}

impl<T> FooABoxClone for T
where
    T: 'static + Foo<Category = A> + Clone,
{
    fn clone_box(&self) -> Box<dyn Foo<Category = A>> {
        Box::new(self.clone())
    }
}

// Compilation error: Foo<Category = A> does not implement Clone
impl Clone for Box<dyn Foo<Category = A>> {
    fn clone(&self) -> Self {
        FooABoxClone::clone_box(&**self)
    }
}

// Compilation error: type parameter `T` must be used as the type parameter for some local type
impl<T> Clone for Box<T>
where
    T: 'static + Foo<Category = A> + Clone,
{
    fn clone(&self) -> Self {
        FooABoxClone::clone_box(&**self)
    }
}

0 个答案:

没有答案