Rust:借用的值必须对静态生命周期有效

6
我正在使用Rust开发一个玩具光线追踪器项目,但遇到了与生命周期相关的错误。我已将代码简化为以下自包含的失败案例:
struct Material {}

pub struct Sphere<'a> {
    material: &'a Material,
}

pub trait AnySceneObject {}

impl<'a> AnySceneObject for Sphere<'a> {}

pub struct Scene {
    objects: Vec<Box<AnySceneObject>>,
}

fn main() {
    let material = Material {};
    let boxed_sphere: Box<AnySceneObject> = Box::new(Sphere { material: &material });
    Scene { objects: vec![boxed_sphere] };
}

哪个抱怨

error[E0597]: `material` does not live long enough
  --> main.rs:17:74
   |
17 |     let boxed_sphere: Box<AnySceneObject> = Box::new(Sphere { material: &material });
   |                                                                          ^^^^^^^^ does not live long enough
18 |     Scene { objects: vec![boxed_sphere] };
19 | }
   | - borrowed value only lives until here
   |
  = note: borrowed value must be valid for the static lifetime...

error: aborting due to previous error(s)

我希望使用traits来定义场景中的对象,但是我希望Scene对象拥有它们。 我的当前理解是这意味着我需要Box或等效物,因为特质对象大小未知。

我还想让对象共享对Material的引用,因为它们不会有很多,尽管它们相对简单并且可以使用Copy,但我不希望有成千上万个相同的副本(因此使用&'a Material)。

我很困惑在这里传递&material为什么有问题:由于值是最后一个先被删除,所以Scene会首先被删除,允许boxed_sphere被删除(因为它现在拥有一个拥有BoxVec),然后可以删除material,没有问题? 因为我将名为material的值保留了整个函数范围,所以它似乎应该至少与函数中的另外两个值一样长寿。

另外有点令人困惑的是,注释掉Scene的实例化可以解决问题,原因我不理解。

1个回答

8

首先,如果您有成千上万的场景对象,将它们放在一个盒子里(基本上是一个堆对象)绝对不是一个好主意。

这个错误被称为因为Box的内容不能有任何可能过期的引用。您可以移动一个Box,并且它可能永远不会被删除,直到进程结束,因此它持有的任何引用都必须具有'static生命周期。

您可以通过使用Box<T + 'a>来表示它将具有有限的寿命来修复它:

pub struct Scene<'a> {
    objects: Vec<Box<AnySceneObject + 'a>>,
}

您也可以使用Vec<&Trait>来存储实现特质的不同对象的引用集合。以下代码可编译:

pub struct Scene<'a> {
    objects: Vec<&'a AnySceneObject>,
}

fn main() {
    let material = Material {};
    let sphere = Sphere { material: &material };
    Scene {
        objects: vec![&sphere] 
    };
}

如果您知道您的特质的所有可能实现,则可以将其替换为枚举。这将使代码执行更高效,因为您将拥有一个拥有枚举而不是引用的向量。

问题!(1)这些对象不管怎样都会在堆上吗?在这种情况下,Box是否添加了第二层间接性?(2)在您的第二个代码片段中,它可以工作是因为main拥有单个sphere句柄,但如果我动态生成一个Vec <&AnySceneObject>(比如从文件),某些东西需要拥有这些对象(对吧?),因此我使用了Box(我意识到这在我的简化示例中被省略了)。 (3)推断的'static来自哪里?这是因为它在main中吗?(4)在这种情况下,枚举听起来更好。我在哪里可以阅读有关它们与引用在此上下文中的比较的信息? - skelley

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接