Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

rust: borrowed value must be valid for the static lifetime [duplicate]

Tags:

rust

I'm working on a toy ray tracer project in Rust and am hung up on a lifetime-related error. I've stripped down my code to the following self-contained failing case:

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

which complains

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)

I want to use traits to define objects in the scene, but I want the Scene object to own them. My current understanding is that this means I need Box or something equivalent because trait objects are of unknown size.

I also want objects to share references to Materials, since there won't be that many of them and though they're relatively simple and Copyable, I don't want literally tens or hundreds of thousands of identical copies of the same thing (hence using &'a Material).

I'm confused why it's problematic to pass &material here though: since values are dropped latest-first, wouldn't Scene be dropped first, allowing boxed_sphere to be dropped (since it now owns a Vec that owns that Box), which it then is, allowing material to be dropped, no problem? It seems like it should live at least as long as the other two values in the function, since I'm holding onto the value with the name material for the scope of the whole function.

Also somewhat confusingly, commenting out the instantiation of Scene fixes the issue for reasons I don't understand.

like image 319
stuffy Avatar asked Oct 27 '17 00:10

stuffy


People also ask

What does static lifetime mean in Rust?

Reference lifetime. As a reference lifetime 'static indicates that the data pointed to by the reference lives for the entire lifetime of the running program. It can still be coerced to a shorter lifetime.

What does&'static mean in Rust?

A static item is similar to a constant, except that it represents a precise memory location in the program. A static is never "inlined" at the usage site, and all references to it refer to the same memory location. Static items have the static lifetime, which outlives all other lifetimes in a Rust program.


1 Answers

First of all, if you have hundreds of thousands of scene objects, putting them in a box (which is basically a heap object) is definitely not a good idea.

The error is called because the Box's content must not have any reference that might expire. You can move a Box around and it may never be deleted until the end of the process, so any references it holds must have 'static lifetime.

You can fix it by using Box<T + 'a> to indicate that it will have a limited lifetime:

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

You can also use Vec<&Trait> to store a collection of references to different objects implementing a trait. The following code compiles:

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

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

If you know all possible implementations of your trait, you can replace it with a enum. This would make the code more performant, as you would have a vector owning enums instead of references.

like image 70
Pavel Strakhov Avatar answered Nov 15 '22 10:11

Pavel Strakhov