`self` does not live long enough when self has static lifetime

I have codes like this:

pub struct Bar {
}

struct Foo {}

impl Foo {
    fn add(self, notification: Box<dyn FnOnce(&Self) + Sync + Send>) {}
}

impl Bar {
    fn allocate(&'static mut self, t: Foo) {
        t.add(
            Box::new(|x| {
                self.echo();
            }),
        )
    }
    fn echo(&self) {}
}

The compiler will report:

error[E0597]: `self` does not live long enough
  --> dice_engine/src/renderer/allocator/block_allocator/mod.rs:14:17
   |
13 |               Box::new(|x| {
   |               -        --- value captured here
   |  _____________|
   | |
14 | |                 self.echo();
   | |                 ^^^^ borrowed value does not live long enough
15 | |             }),
   | |______________- cast requires that `self` is borrowed for `'static`
16 |           )
17 |       }
   |       - `self` dropped here while still borrowed

I don't understand why self is dropped at the end of the function since it has static lifetime, and what's more, if I copy this code to a brand-new project, it will compile.

So what did I do wrong?

P.S. The reason why I don't use Arc<Self> is that in the real case I do need to modify something by referring to a mut self, and Arc<Mutex<Self>> is not allowed.

Lifetimes do not control how long something lives, rather your code structure (where does it go out of scope and so on) controls that. Lifetimes are claims about how long it lives for, and the compiler will check whether they match with the code structure.

To fix this, you must fix the code structure so that it doesn't go out of scope. You can do this using Box::leak(Box::new(val)) to prevent it from being destroyed.

A better option is to not use static here at all. You should probably be using an Arc or Rc instead of a static reference.

1 Like

Do you mean to use Box::leak(Box::new(Foo{})) ? My plan is to create a static value of foo, like this:

lazy_static! {
     static ref FOO: Mutex<Foo> = Mutex::new(Foo {});
}

But I guess that where there's a static foo or not will not affect the checking of function allocate, can you explain more (and why it compiles in other projects)?

If you borrowed the value inside a Mutex for 'static the Mutex would have to be permanently locked.

Aha, I did not understand that you had it in a global. However, the mutex is a problem. A lifetime is actually the duration of the borrow, not how long it lives for. You are only allowed to borrow it for as long as the mutex is locked for, so the only way to get a static reference is to lock it forever, which you don't want.

However, you can get a static reference to the mutex itself.

1 Like

The reason why I don't use Arc<Self> is that in the real case I do need to modify something by referring to a mut self, and Arc<Mutex<Self>> is not allowed.

Could you give me some pseudo-code?I didn't get your suggestion :joy:

Well, if you store a Mutex<Foo> in a global, then this is possible:

impl Foo {
    fn add(self, notification: Box<dyn FnOnce(&Self) + Sync + Send>) {}
}

fn add_global_bar(foo: Foo, bar: &'static Mutex<Foo>) {
    foo.add(Box::new(|x| { bar.lock().echo(); }));
}

However, what is allowed is this:

struct Bar {
    inner: Arc<Mutex<BarInner>>,
}
struct BarInner {
    ... fields from your Bar struct ...
}
1 Like

Hi Alice, I fix the error by following your suggestion, but I am still curious about the error message,
according to this line:

4 | |                 self.echo();
  | |                 ^^^^ borrowed value does not live long enough

Does that mean the self in the course is not a &'static mut Self (in this case, I do want it to be a &'static Self, without the mut)?

That error message means that you are unable to create a &'static Self because you are not actually able to create a borrow of self that lasts until the program ends.

Then why it compiles in playground?

You have to click the share button to get a link containing your code.

I'm sorry, first time to use playground, here's the link

&'static mut self is the worst combination of the two most awful footguns in Rust. It's a complete dead-end, and there's no hope making it work.

&'static mut is a never-ending exclusive access to leaked memory. Such type very rarely has any legitimate use because:

  1. it's leaked, and if you have something like an event handling system you don't want to be leaking all the time
  2. it's strictly exclusive — forever — so it can't be shared between multiple objects, which in case of event handlers is also a very awkward limitation. If you can actually make them work with an exclusively owned object, then a regular Box will work too, and not leak.

When you combine &'static mut with self you get a method that can be called only once ever [1]:

When the compiler tells you to use &'static consider it an invalid suggestion. What it's really trying to say is that in this context all temporary references are forbidden, and can't be made to work. You really really really have to use Arc or some other approach that doesn't involve references. If you need to mutate data behind Arc, you need to add Mutex or atomics.

For callbacks you will need to use for<'a> FnMut(&'a T) syntax. This for<'a> allows you to pass objects temporarily to them (necessary to pass things locked by a Mutex) instead of tying them to some way-too-long lifetime of the outer object or trait.


  1. unless you return self from the method and use the returned object, but that's not a practical solution here ↩︎

3 Likes

There's some sort of disconnect between the example code (which compiles) and the error you pasted. I would expect the method to be problematic to use ala @kornel's example, but not to emit an error about the body of the method. Do you have a more complete example of the error-emitting code?

It part of my game engine project, I'll try to delete all unrelated codes and upload an error-emitting project later.