Getting "borrowed value does not live long enough" Error While Trying to Pass a Boxed dyn Trait into a Function

Viewed 821

I'm new to rust and I get really confused by the behavior of the borrow checker.

trait Foo {
  fn foo(&self);
}

struct Bar<'a> {
  pub f : &'a Vec<i32>
}

impl<'a> Foo for Bar<'a> {
  fn foo(&self) {
    for i in self.f {
      println!("{}", i);
    }
  }
}

fn call(b : &Box<dyn Foo>) {
  b.foo();
}

fn main() {
  let a = vec!(1,2,3);
  let b : Box<dyn Foo> = Box::new(Bar {f : &a});
  call(&b)
}

By compiling this piece of code I get:

error[E0597]: `a` does not live long enough
  --> main.rs:23:44
   |
23 |   let b : Box<dyn Foo> = Box::new(Bar {f : &a});
   |                          ------------------^^--
   |                          |                 |
   |                          |                 borrowed value does not live long enough
   |                          cast requires that `a` is borrowed for `'static`
24 |   call(&b)
25 | }
   | - `a` dropped here while still borrowed

Could someone explain to me why in this case a does not live long enough? It seems to me that it will live through the entire life cycle of the program.

2 Answers

By default, Box<dyn Foo> means Box<dyn Foo + 'static>, so only 'static values can be stored in Box<dyn Foo>. a is created inside a function, so it does not live for 'static.

You can adjust the lifetime by using a lifetime parameter:

fn call<'a>(b: &Box<dyn Foo + 'a>) {
    b.foo();
}

(playground)

Note that the main function is not "the entire cycle of the program". There is some initialization code that is run before main gets called, and some teardown code that is run after it returns. So the Rust compiler does not handle main differently from any other function.

In your case, since you don't specify it explicitly, the compiler assumes that the parameter to call is a reference to a Box<dyn Foo +'static>. You can override this by specifying the lifetime yourself:

fn call<'a>(b: &Box<dyn Foo + 'a>) {
    b.foo();
}

Playground

Related