Borrow Might Be Used Here (at end of main fn)

I am having some trouble with lifetimes it seems.

The compiler is saying my app which takes a lifetime won't live long enough, but I'm scratching my head. The compiler says it might be borrowed at the end of main when app is dropped but I clearly am not using it.

The code:

// In app module
pub struct App<'app> {
    event_handler: EventHandler<'app>,
    state: Rc<RefCell<State>>,
}

// In main
fn main() -> io::Result<()> {
    let mut terminal = ratatui::init();

    let mut app = App::init();

    ratatui::restore();

    app.run(&mut terminal) // returns result
}

Error when running:

error[E0597]: `app` does not live long enough
  --> src/main.rs:12:5
   |
8  |     let mut app = App::init();
   |         ------- binding `app` declared here
...
12 |     app.run(&mut terminal)
   |     ^^^ borrowed value does not live long enough
13 | }
   | -
   | |
   | `app` dropped here while still borrowed
   | borrow might be used here, when `app` is dropped and runs the destructor for type `App<'_>`

I tried creating a let binding:

fn main() -> io::Result<()> {
    let mut terminal = ratatui::init();

    let mut app = App::init();

    ratatui::restore();

    let result = app.run(&mut terminal);

    result
}

But I get this error:

error[E0597]: `app` does not live long enough
  --> src/main.rs:12:18
   |
8  |     let mut app = App::init();
   |         ------- binding `app` declared here
...
12 |     let result = app.run(&mut terminal);
   |                  ^^^ borrowed value does not live long enough
...
15 | }
   | -
   | |
   | `app` dropped here while still borrowed
   | borrow might be used here, when `app` is dropped and runs the destructor for type `App<'_>`

please show the type signature of App::run().

without more context, I would guess you are might be running into the borrowing something forever pitfall.

2 Likes
pub fn run(&'app mut self, terminal: &mut DefaultTerminal) -> io::Result<()>
let mut app: App<'_> = App::init();

there's it is! I guessed it!

&'app mut self is short for self: &'app mut App<'app>, and this is exactly the pattern for the "borrowing forever" problem, as described in the linked article.

remove the 'app lifetime annotation for self, just use &mut self, you should be good.

1 Like

I'm guessing they'll get a compiler error instead. Consider:

pub struct App<'app> { ... }

fn main() -> io::Result<()> {
    let mut app = App::init();
}

The App<'app> lifetime is coming from nowhere when returned from init -- presumably to be inferred elsewhere. Probably the lifetime only exists as an attempt to be self-referencial. Trying to store a borrow of State in the event_handler field?

So my guess is that a larger redesign will be required.


In other words: If you remove the 'app lifetime annotation and just use &mut self in fn run, and the compiler suggests you add the annotation back, you're almost surely trying to be self-referencial and should seek a different approach. Rust doesn't support storing a lifetime-annotated borrow of one your other fields in the same struct in any practical sense.

1 Like