Borrowing rule having issues

in my rust code, I have this code:

pub struct Projects<'a>
{
    pub scene: &'a mut Scene,
}
struct Scene
{
    x: u8,
}

fn main()
{
    let mut scene = Scene{x: 10};
    let mut powerobject = Projects
    {
        scene: &mut scene,
    };
    engine.update_loop(move
    |
        renderer,
        window,
        objects,
        input,
        _,
        plugins
    |
    {
        some_function(powerobject: &mut Projects);
    });
}

Which works fine, however if I did this in some_function()

fn some_function(powerobject: &mut Projects)
{
   let scene = &mut powerobject.scene
}

Then I get an error in these lines:

    engine.update_loop(move
    |
        renderer,
        window,
        objects,
        input,
        _,
        plugins
    |

Which is:

cannot move out of 'scene', because it is borrowed move out of scene occurs over here.

How do I fix this?

Changing the body of that function can't influence callers.

What's the full error when you run cargo build in a console?

To be honest Scene's structure has totally different fields, reason why I didn't paste the original values here is cause it is all pointing to other structures etc. I just wanted to give a simple example but anyways here is the full error:

error[E0597]: `scene` does not live long enough
    --> src/main.rs:723:16
     |
713  |       let mut scene = Scene::init(0);
     |           --------- binding `scene` declared here
...
723  |           scene: &mut scene,
     |                  ^^^^^^^^^^ borrowed value does not live long enough
...
745  | /     engine.update_loop(move
746  | |     |
747  | |         renderer,
748  | |         window,
...    |
1414 | |         }, &window)
1415 | |     }).unwrap();
     | |______- argument requires that `scene` is borrowed for `'static`
1416 |
1417 |   }
     |   - `scene` dropped here while still borrowed

error[E0505]: cannot move out of `scene` because it is borrowed
    --> src/main.rs:745:24
     |
713  |        let mut scene = Scene::init(0);
     |            --------- binding `scene` declared here
...
723  |            scene: &mut scene,
     |                   ---------- borrow of `scene` occurs here
...
745  |        engine.update_loop(move
     |   _____-__________________^
     |  |_____|
     | ||
746  | ||     |
747  | ||         renderer,
748  | ||         window,
...    ||
752  | ||         plugins
753  | ||     |
     | ||_____^ move out of `scene` occurs here

I guess the issue is right here:

    let mut powerobject = view_modes_argument_passer::Projects
    {
        scene: &mut scene,
    };

where scene does not live long enough.

let scene = &mut powerobject.scene

causes it to not live long enough, not too sure how to fix this?

This is the method I'm guessing?

Let me know if my guess is wrong. But if it's right...

It requires a 'static closure, which means you can't capture anything with a borrow of anything (unless it's also 'static). You might be able to use Arcs or something instead.

I'm less sure about the move error, but it's moot if you can't fix the lifetime error.

2 Likes

am I able to get away without using Arcs if I used static in the structure field definitions?

You can't reasonably get a &'static mut without leaking memory, so I doubt it's workable how you want.

1 Like

Only when I do this:

let scene = &mut powerobject.scene then this issue occurs otherwise it is fine. Why is that though?

I don't have enough context to figure that one out.

If I read your sample code correctly, this occurs because scene is allocated on the stack and would be dropped when it goes out of scope. This drop is guaranteed to be shorter than 'static for all the compiler is concerned, even if the stack frame is in main().

As pointed out earlier, the closure passed to update_loop() requires that it doesn't borrow anything from the stack. If Arc is unacceptable, you could heap-allocate and leak the box, ensuring its destructor will never run.

pub struct Projects { // CHANGED: No longer needs a named lifetime
    pub scene: &'static mut Scene, // CHANGED: Now valid for `'static`
}

fn main() {
    let scene = Box::leak(Box::new(Scene { x: 10 }));
    let mut projects = Projects { scene };

    // ... everything else is the same
}
1 Like

I could do that, but I was suggested to put the variable inside the update_loop which is what I did and it works.

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.