Eric
Eric

Reputation: 21

Compilation error when calling a function defined in trait that returns a reference type: borrowed value does not live long enough

Compilation error when calling a function defined in trait that returns a reference type: borrowed value does not live long enough

Here is a sample reproduction of my problem:

use std::rc::Rc;

trait Bundle<'a> {
    fn id(&'a self) -> &'a str;
}

struct Demo {
    id: String,
}

impl<'a> Bundle<'a> for Demo {
    fn id(&'a self) -> &'a str {
        &self.id
    }
}

fn x(bundle: Rc<dyn Bundle<'_>>, file: &str) -> String {
    let id = bundle.id();
    format!("bundle/{}/{}", id, file)
}

fn main() {
    let demo = Rc::new(Demo {
        id: String::from("demo"),
    });
    println!("{}", x(demo as Rc<dyn Bundle>, "hello.txt"));
}

The compiler gives the following error:

error[E0597]: `bundle` does not live long enough
  --> src/main.rs:18:14
   |
17 | fn x(bundle: Rc<dyn Bundle<'_>>, file: &str) -> String {
   |      ------ has type `Rc<dyn Bundle<'1>>`
18 |     let id = bundle.id();
   |              ^^^^^^^^^^^
   |              |
   |              borrowed value does not live long enough
   |              argument requires that `bundle` is borrowed for `'1`
19 |     format!("bundle/{}/{}", id, file)
20 | }
   | - `bundle` dropped here while still borrowed

I'm a newbie and in my understanding, after the format!() statement at line 19, I no longer borrow bundle. So why rustc thinks it "still borrowed"?

Upvotes: 1

Views: 53

Answers (1)

Eric
Eric

Reputation: 21

I made a stupid mistake. Thanks to the answer given by @jmb in the comments section, I now changed the code to the following to fixup it:

use std::rc::Rc;

trait Bundle {
    fn id(&self) -> &str;
}

struct Demo {
    id: String,
}

impl Bundle for Demo {
    fn id(&self) -> &str {
        &self.id
    }
}

fn x(bundle: Rc<dyn Bundle>, file: &str) -> String {
    let id = bundle.id();
    format!("bundle/{}/{}", id, file)
}

fn main() {
    let demo = Rc::new(Demo {
        id: String::from("demo"),
    });
    println!("{}", x(demo as Rc<dyn Bundle>, "hello.txt"));
}

BTW, I have also tried to continue using the explicit lifecycle. The generic argument should be on the function and not on the trait.

trait Bundle {
    fn id<'a>(&'a self) -> &'a str;
}

Upvotes: 1

Related Questions