How do lifetimes work in methods which use self?

I'm having trouble which and I can't grasp why. What I have are these two structs

pub struct RenderAssetManager<'a> {
    pub renderables: Vec<Renderable<'a>>,
    pub textures: HashMap<String, Texture2D>,
}

pub struct Renderable<'a> {
    x: f32,
    y: f32,
    visible: bool,
    texture: &'a Texture2D,
    animated_info: Option<AnimationInfo>
}

so far, so good. What I had in mind is to do this in an OOP style and implement methods for RenderAssetMannager, here they are

impl<'a> RenderAssetManager <'a>{

    pub fn new() -> RenderAssetManager<'a>{
        let x = RenderAssetManager{ renderables: vec![], textures: Default::default() };
        x
    }

    pub async fn insert_texture(&mut self, path: &str){
        if !self.textures.contains_key(path){
            let t = load_texture(path).await;
            if (t.is_ok()){
                self.textures.insert(path.to_string(), t.unwrap());
            } else {
                panic!("Texture failed!")
            }
        }
    }
    pub async fn insert_renderable(&'a mut self, path: &str){

        let renderable = Renderable{
            x: 0.0,
            y: 0.0,
            visible: false,
            texture: self.textures.get(path).unwrap(),
            animated_info: None,
        };


        self.renderables.push(renderable);
    }
}

Which by itself does compile. My idea was to do this then in the main method

async fn main() {
    let mut manager = renderables::RenderAssetManager::new();

    let path = "textures/ferris.png";
    manager.insert_texture(path).await;
    manager.insert_renderable(path).await;
    manager.textures.get(path);
}

Which causes this issue

error[E0502]: cannot borrow `manager.textures` as immutable because it is also borrowed as mutable
  --> src/main.rs:22:5
   |
21 |     manager.insert_renderable(path).await;
   |     ------------------------------- mutable borrow occurs here
22 |     manager.textures.get(path);
   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^
   |     |
   |     immutable borrow occurs here
   |     mutable borrow later used here

But why exactly does it remain borrowed? I can call the method
manager.insert_texture(path).await;
multiple times and there's no issue. The issue only arrives when using the manager.insert_renderable(path).await;, which I assume happens because of lifetimes. But to my understanding, there's not really much that you can do to change that. It only has one lifetime that's same as the stuct ones. Which I thought would mean that the method doesn't keep it after it's done. Any clues on what I should do?

You are trying to make a self refererential struct - you can't do this with normal references and probably shouldn't do this in general.

This topic may have more information: https://users.rust-lang.org/t/how-can-we-teach-people-about-self-referential-types/65362

2 Likes

For a brief explanation of what's going on with the lifetimes, you can see here and click on to the following two sections as well.

2 Likes

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.