生锈:借用的值必须对静态寿命有效

时间:2017-10-27 00:46:48

标签: rust

我正在研究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删除({1}}因为它现在拥有一个拥有Vec)的Box,它就是这样,允许material被删除,没问题?看起来它应该至少与函数中的其他两个值一样长,因为我保留了整个函数范围的名称为material的值。

同样有些令人困惑的是,评论Scene的实例化解决了这个问题,原因我不明白。

1 个答案:

答案 0 :(得分:4)

首先,如果你有数十万个场景对象,把它们放在一个盒子里(基本上就是一个堆对象)绝对不是一个好主意。

调用错误是因为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] 
    };
}

如果您了解特征的所有可能实现,则可以用枚举替换它。这将使代码更高效,因为您将拥有一个拥有枚举而不是引用的向量。