CrociDB
CrociDB

Reputation: 1234

Lifetime Problem: "types have different lifetimes, but data from 'self' flows into..."

I have this code:

#[derive(Clone, Copy)]
pub struct HitRecord<'a> {
    pub t: f32,
    pub p: Vector3<f32>,
    pub normal: Vector3<f32>,
    pub material: Option<&'a Material>,
}

pub struct Sphere<T>
where
    T: Material,
{
    pub center: Vector3<f32>,
    pub radius: f32,
    pub material: T,
}

impl<T> Sphere<T> {
    fn hit<'a, 'b>(&'a self, ray: &Ray, t_min: f32, t_max: f32, record: &'b mut HitRecord) -> bool
    where
        'a: 'b,
    {
        record.material = Some(&self.material);
    }
}

I understand that record must have a shorter lifetime than self, so I assigned different lifetimes to them and set 'a to enclose 'b. But I'm still getting this:

error[E0623]: lifetime mismatch
  --> src\tracer\sphere.rs:54:35
   |
30 |     fn hit<'a, 'b>(&'a self, ray:&Ray, t_min:f32, t_max:f32, record:&'b mut HitRecord) -> bool where 'a: 'b {
   |                    --------                                                 ---------
   |                    |
   |                    these two types are declared with different lifetimes...
...
54 |                 record.material = Some(&self.material);
   |                                   ^^^^^^^^^^^^^^^^^^^^ ...but data from `self` flows into `record` here

I have beeem fighting this lifetime problem for quite a few hours now and I don't understand what's going on here; what am I doing wrong?

Upvotes: 4

Views: 2475

Answers (1)

darkwisebear
darkwisebear

Reputation: 131

The lifetime of the reference inside HitRecord has to be set to the same (or less) as the lifetime of &self so that the reference from record to self is correct. You don't even have to explicitly set up a relation between 'a and 'b because it's not the lifetime of record itself that matters but the lifetime of the struct member material. This signature should work:

fn hit<'a>(&'a self, ray:&Ray, t_min:f32, t_max:f32, record:&mut HitRecord<'a>) -> bool

Edit: One thing I've seen that you might not be aware of is that you're creating a trait object, i.e. something that enables dynamic dispatch. If you don't need that, you might want to change the declaration of HitRecord to

#[derive(Clone, Copy)]
pub struct HitRecord<'a, T: Material> {
    pub t: f32,
    pub p: Vector3<f32>,
    pub normal: Vector3<f32>,
    pub material: Option<&'a T>
}

This way, you fix the struct to a certain, statically known type implementing Material which enables static, compile time dispatch.

Upvotes: 4

Related Questions