0

I'm new to Rust's lifetimes concept and can't wrap my head around a particular piece of code. I've been working with Rust's SDL bindings and its Texture/TextureCreator classes and the problem basically boils down to the following scheme:

struct Creator;

impl Creator {
    fn create(&self) -> Creature {
        Creature { creator: &self }
    }
}

struct Creature<'a> {
    creator: &'a Creator,
}

struct MyStruct<'a> {
    creator: Creator,
    creatures: Vec<Creature<'a>>,
}

impl<'a> MyStruct<'a> {
    fn new() -> MyStruct<'a> {
        MyStruct {
            creatures: Vec::new(),
            creator: Creator,
        }
    }

    fn create(&mut self) {
        let new_creature = self.creator.create();
        self.creatures.push(new_creature);
    }
}

fn main() {
    let mut my_struct = MyStruct::new();
    my_struct.create();
}

The actual problem lies inside MyStruct::create method. If I try to compile the above code I get:

error[E0495]: cannot infer an appropriate lifetime for autoref due to con
flicting requirements
  --> src/main.rs:27:41
   |
27 |         let new_creature = self.creator.create();
   |                                         ^^^^^^
   |
note: first, the lifetime cannot outlive the anonymous lifetime #1 define
d on the method body at 26:5...
  --> src/main.rs:26:5
   |
26 | /     fn create(&mut self) {
27 | |         let new_creature = self.creator.create();
28 | |         self.creatures.push(new_creature);
29 | |     }
   | |_____^
note: ...so that reference does not outlive borrowed content
  --> src/main.rs:27:28
   |
27 |         let new_creature = self.creator.create();
   |                            ^^^^^^^^^^^^
note: but, the lifetime must be valid for the lifetime 'a as defined on t
he impl at 18:6...
  --> src/main.rs:18:6
   |
18 | impl<'a> MyStruct<'a> {
   |      ^^
   = note: ...so that the expression is assignable:
           expected Creature<'a>
              found Creature<'_>

The interesting thing is that when I comment out this line inside MyStruct::create:

self.creatures.push(new_creature);

it compiles just fine.

My assumption is that it can lead to the following problem - a newly created new_creature has a reference to the creator which is owned by my_struct. Now, if that new_creature is then owned by the creatures vector, I can't really call any method on my_struct that borrows itself as mut because at that point there will be:

  • a reference to creator inside my_struct
  • a mutable reference to my_struct inside the method's body (and therefore to my_struct.creator)

However, this is how I see it from my point of view. From the compiler's standpoint it's about lifetimes and don't quite get it. So I have the two following questions:

  1. Why does the compiler complain about lifetimes in this case?
  2. How can I go about storing Vec<Creature> in a struct? Should I make sure that I don't keep both Creator and Vec<Creature> in the same struct to avoid the aforementioned issue?
cosmic.
  • 41
  • 8
  • See also [Is there a way to store a texture inside a struct using rust-sdl2?](https://stackoverflow.com/q/56051593/155423) – Shepmaster May 10 '19 at 15:58

1 Answers1

0

The compiler is trying to tell you that it is expecting a very specific lifetime in Creature<'a> but the code actually produces a generic lifetime Creature<'_>. That is, the lifetime bound on Creature must be 'a but you are writing method create() for any lifetime '_.

Change create() to

fn create(&'a mut self) {
    let new_creature = self.creator.create();
    self.creatures.push(new_creature);
}

and it will compile: Instead of "any lifetime &mut self could ever have" you now have "&mut self must have lifetime 'a".

user2722968
  • 13,636
  • 2
  • 46
  • 67
  • I've already tried it but it doesn't solve my problem at all. If I call `my_struct.create()` once again, the compiler tells me: `error[E0499]: cannot borrow 'my_struct' as mutable more than once at a time` – cosmic. May 10 '19 at 16:00
  • While this technically solves the error, it makes the value immovable. Try adding `{my_struct}` at the end of `main`. – Shepmaster May 10 '19 at 16:01