如何基于 `&[Box<dyn CustomTrait>]` 创建向量?

How to create a vector based on an `&[Box<dyn CustomTrait>]`?

我有一个自定义特征,用作切片中的元素类型:

pub trait IConstraint {
  // members here
}

pub struct Scenario<'a> {
  pub constraints: &'a [Box<dyn IConstraint>]
}

我想提供一个 add_constraint 方法来执行切片的写时复制。像这样:

impl<'a> Scenario<'a> {
    pub fn add_constraint(&mut self, constraint: Box<dyn IConstraint<TNodeState>>) {
        let mut constraints: Vec<Box<dyn IConstraint<TNodeState>>> = Vec::new();
        constraints.copy_from_slice(self.constraints);
        constraints.push(constraint);
        self.constraints = &constraints;
    }
}

问题是我得到这个错误:

the trait bound Box<dyn IConstraint<TNodeState>>: std::marker::Copy is not satisfied the trait std::marker::Copy is not implemented for Box<dyn IConstraint<TNodeState>>

好的,所以 Box<T> 没有实现 Copy 特性。很公平。但是我该如何解决呢?理想情况下,我会重用这些框或至少是约束,因为它们是不可变的。但是如果由于 rust 所有权规则我不能这样做,我怎么能在盒子类型上实现 Copy 特性呢?我尝试了各种方法,但它们都会产生错误。

此尝试产生“在具有析构函数的类型上不允许复制”:

impl<TNodeState> Copy for Box<dyn IConstraint<TNodeState>> {
}

克隆呢?我可以切换到 constraints.clone_from_slice(self.constraints);,但随后在 IConstraint 上实现 Clone 特性会产生一堆“IConstraint 无法成为对象”错误。

即使我能让 box 成为可克隆的,那么我当然会从我的 add_constraint 方法中得到预期的借用生命周期缺陷:

borrowed value does not live long enough

所以我是否必须完全放弃我的 add_constraint 函数想法并强制我的结构的所有者手动复制它?考虑到我的实际结构包含 3 个字段,这变得乏味,因为所有者现在必须将字段解构为本地字段以删除不可变借用,从而允许原始向量发生变异:

fn add_remove_constraint() {
    let mut scenario = Scenario::<&str, bool, 3_usize>::new(&["A", "B", "C"]);
    let mut constraints: Vec<Box<dyn IConstraint<bool>>> = Vec::new();
    constraints.push(Box::new(SelectionCountConstraint {
        nodes: [1, 2],
        min: 1,
        max: 2,
    }));
    scenario = Scenario {
        constraints: &constraints,
        ..scenario
    };

    assert_eq!(1, scenario.get_constraints().len());
    let nodes = scenario.nodes;
    let selection_state = scenario.selection_state;
    constraints.pop();
    scenario = Scenario {
        constraints: &constraints,
        nodes,
        selection_state,
    };
    assert_eq!(0, scenario.get_constraints().len());
}

我想你完全错了。正如评论中所说,你的 add_constraint 永远不会起作用,因为你首先引用了你在同一个函数中创建的东西(函数范围到期后将被删除)。

您应该拥有一个包含这些 IConstraint 特征的容器,但在内部您应该有一个 &dyn IConstraintBox<dyn IConstraint>

在那种情况下向它们添加一个项目是微不足道的:

pub trait IConstraint {
  // members here
}

pub struct Scenario<'a> {
  pub constraints: Vec<&'a dyn IConstraint>
}

impl<'a> Scenario<'a> {
    pub fn add_constraint(&mut self, constraint: &'a dyn IConstraint) {
        self.constraints.push(constraint);
    }
}

Playground

这应该可以解决您的问题,因为 参考文献是 Copy