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

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;
    }
}

问题是我遇到了以下错误:

trait 界限Box<dyn IConstraint<TNodeState>>: std::marker::Copy不满足

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

此try 会产生"在具有析构函数的类型上不允许复制":

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

克隆呢?我可以切换到constraints.clone_from_slice(self.constraints);,但在IConstraint上实现Clone trait会产生一系列"IConstraint不能生成对象"错误.

即使我可以让box可克隆,当然我也会从我的add_constraint方法中得到预期的borrow 生命周期 缺陷:

借来的价值活得不够长

那么,我是否必须抛弃我的add_constraint个函数的 idea ,并强制我的 struct 的所有者手动复制它?鉴于我的实际 struct 包含3个字段,这变得很乏味,因为所有者现在必须将字段解构为局部变量,以便删除不可变的borrow ,从而允许原始向量发生变异:

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());
}

推荐答案

我想你全搞错了.正如 comments 中所说,您的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

这应该可以解决你references are 100年以来的问题.

Rust相关问答推荐

为什么函数不接受选项T参数的所有权?

为什么对不可复制数据的引用的取消引用没有O权限来避免Rust中的双重释放?

从Type::new()调用函数

如何定义实现同名但返回类型不同的 struct 的函数

铁 rust 中的泛型:不能将`<;T作为添加>;::Output`除以`{Float}`

告诉Rust编译器返回值不包含构造函数中提供的引用

无法定义名为&new&的关联函数,该函数的第一个参数不是self

在IntoIter上调用.by_ref().Take().rev()时会发生什么情况

为什么Rust不支持带关联常量的特征对象?

Nom 解析器无法消耗无效输入

Rust 中的自动取消引用是如何工作的?

简单 TCP 服务器的连接由对等重置错误,mio 负载较小

Rust 中的生命周期:borrow 的 mut 数据

如何判断服务器是否正确接收数据

为什么 File::read_to_end 缓冲区容量越大越慢?

第 7.4 章片段中如何定义 `thread_rng`

使用 `.` 将 T 转换为 &mut T?

当特征函数依赖于为 Self 实现的通用标记特征时实现通用包装器

传递 Option<&mut T> 时何时需要 mut

当值是新类型包装器时,对键的奇怪 HashMap 生命周期要求