我正在try 实现一些类似于下面这个最小示例的东西:

trait Bar<T> {}

struct Foo<T> {
    data: Vec<Box<Bar<T>>>,
}

impl<T> Foo<T> {
    fn add<U: Bar<T>>(&mut self, x: U) {
        self.data.push(Box::new(x));
    }
}

因为 rust 默认为(据我所知)按所有权传递,我的心智模型认为这应该有效.add方法拥有对象x的所有权,并且能够将该对象移动到Box中,因为它知道完整的类型U(而不仅仅是特征Bar<T>).一旦移动到Box,盒子内物品的生命周期 应与盒子的实际生命周期 挂钩(例如,当物体脱离矢量pop()时,物体将被销毁).

然而,编译器显然不同意(而且我肯定知道的比我多一点…),让我考虑添加一个'static生命限定符(E0310).我99%确定那不是我想要的,但我不确定我应该做什么.

为了澄清我的 idea ,帮助识别误解,我的心理模型来自C++背景,是:

  • Box<T>基本上是std::unique_ptr<T>
  • 在没有任何注释的情况下,如果变量为Copy,则按值传递,否则按右值引用
  • 使用参考注释时,&约为const&&mut约为&
  • 默认生存期是词法范围

推荐答案

查看整个错误:

error[E0310]: the parameter type `U` may not live long enough
 --> src/main.rs:9:24
  |
8 |     fn add<U: Bar<T>>(&mut self, x: U) {
  |            -- help: consider adding an explicit lifetime bound `U: 'static`...
9 |         self.data.push(Box::new(x));
  |                        ^^^^^^^^^^^
  |
note: ...so that the type `U` will meet its required lifetime bounds
 --> src/main.rs:9:24
  |
9 |         self.data.push(Box::new(x));
  |                        ^^^^^^^^^^^

具体来说,编译器会让您知道,某些任意类型U might contain a reference可能会发生错误,然后该引用可能会变得无效:

impl<'a, T> Bar<T> for &'a str {}

fn main() {
    let mut foo = Foo { data: vec![] };

    {
        let s = "oh no".to_string();
        foo.add(s.as_ref());
    }
}

那将是个坏消息.

你想要'static年的生命周期 还是参数化的生命周期 取决于你的需要.'static生命周期 更容易使用,但有更多限制.因此,在 struct 或类型别名中声明trait object时,它是默认值:

struct Foo<T> {
    data: Vec<Box<dyn Bar<T>>>,
    // same as
    // data: Vec<Box<dyn Bar<T> + 'static>>,
} 

但是,当用作参数时,trait对象使用lifetime elision并获得唯一的生存期:

fn foo(&self, x: Box<dyn Bar<T>>)
// same as
// fn foo<'a, 'b>(&'a self, x: Box<dyn Bar<T> + 'b>)

这两件事需要配合.

struct Foo<'a, T> {
    data: Vec<Box<dyn Bar<T> + 'a>>,
}

impl<'a, T> Foo<'a, T> {
    fn add<U>(&mut self, x: U)
    where
        U: Bar<T> + 'a,
    {
        self.data.push(Box::new(x));
    }
}

or

struct Foo<T> {
    data: Vec<Box<dyn Bar<T>>>,
}

impl<T> Foo<T> {
    fn add<U>(&mut self, x: U)
    where
        U: Bar<T> + 'static,
    {
        self.data.push(Box::new(x));
    }
}

Rust相关问答推荐

如何从可变Pin中获取不可变Pin?

Rust为什么应用于引用的操作符可以强制,而具有显式类型的let则不能?

为什么在Rust struct 中只允许最后一个字段具有动态大小的类型

当Option为None时,Option数组是否占用Rust中的内存?

如何仅使用http机箱发送http请求?

如何将`Join_all``Vec<;Result<;Vec<;Foo&>;,Anywhere::Error&>;`合并到`Result<;Vec<;Foo&>;,Anywhere::Error&>;`

如何在AVX2中对齐/旋转256位向量?

使用 serde::from_value 反序列化为泛型类型

如何对一个特征的两个实现进行单元测试?

更新 rust ndarray 中矩阵的一行

Button.set_hexpand(false) 不会阻止按钮展开

Rust并发读写引起的死锁问题

如何从trait方法返回std :: iter :: Map?

从 Axum IntoResponse 获取请求标头

rust 中不同类型的工厂函数

切片不能被 `usize` 索引?

使用方法、关联函数和自由函数在 Rust 中初始化函数指针之间的区别

为什么 no_std crate 可以依赖于使用 std 的 crate?

将 (T, ()) 转换为 T 安全吗?

需要括号的宏调用中的不必要的括号警告 - 这是编写宏的糟糕方法吗?