1

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"?

3
  • Remove the explicit lifetime: trait Bundle { fn id(&self) -> &str; }. Commented Mar 28, 2023 at 11:38
  • Thanks, it works! Can you explain why this error occurs after adding the explicit lifetime 'a? Or give some URLs for reference. @Jmb Commented Mar 28, 2023 at 11:44
  • This is basically the same issue as this question: by using the same lifetime in the generic argument Bundle<'a> and in the function prototype id (&'a self) -> &'a str, you're linking both lifetimes together, i.e. you're telling the compiler that bundle must stay borrowed as long as demo lives. Commented Mar 28, 2023 at 11:45

1 Answer 1

1

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;
}
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.