Beginner confusion: lifetimes of App, Window, and callback

I have a App struct, which has a Vec<Box<Window>> that will change as the app runs and windows open and close. The struct Window has a field renderer which I want to use to customize different windows. After some tinkering with function traits I got...

type RenderFn<'a> = dyn Fn() -> () + 'a;
pub struct Window<'a> {
    ...
    renderer: Option<Box<RenderFn<'a>>>

Now the App has a problem, because it wants a lifetime parameter for its Windows, but I'm lost. Should I keep adding lifetime parameters to everything as the compiler is suggesting, and see where it leads me, or can you see I'm already on the wrong track here?

struct App {  // add <'a> ?
    ...
    windows: Vec<Box<Window>>  // add <'a> ?

As you can see these Windows are heap allocated. I thought lifetimes were more for stack allocated stuff where variable lifetimes are more clear.

Very likely wrong track. How are you using renderer? And what are examples of renderer?

Why do you need 'a on RenderFn? Could that be 'static instead?

Well, I haven't got it working yet. I'm copying code from another language where possible, as I try to learn Rust. I need to add a Window parameter to the renderer function. It's going to make calls to Vulkan.

I wanted to make it flexible to take any kind of function or closure, but you're right maybe in this case that is overkill. Closures with captured variables were not working with 'static.

So long as they own (and don't consume) their captures, and those captured values are themselves 'static, it should be fine.

Rust lifetimes are about borrows, generally short-lived borrows, and not long-lived data structures. Don't add lifetimes to your data structures without a specific and solid reason. (It's a common beginner misstep.)

1 Like