I would like to hide the actual implementation that is returned from the create function by returning an impl trait
as in create_trait()
. How could this be done?
trait Names<'a> {
fn names(&'a self) -> &Vec<&'a str>;
}
struct NamesImpl<'b> {
names: Vec<&'b str>,
}
impl<'c> Names<'c> for NamesImpl<'c> {
fn names(&'c self) -> &Vec<&'c str> {
&self.names
}
}
fn create_impl<'i>() -> NamesImpl<'i> {
NamesImpl {
names: vec!["Hello", "world"],
}
}
#[allow(dead_code)]
fn create_trait<'t>() -> impl Names<'t> {
NamesImpl {
names: vec!["Hello", "world"],
}
}
fn main() {
let names_impl = create_impl();
println!("Names: {:?}", names_impl.names());
//This doesn't compile, see error below
let names_trait = create_trait();
println!("Names: {:?}", names_trait.names());
}
I can't wrap my head around the following compile error. Why does it work with create_impl()
but not with create_trait()
?
error[E0597]: `names_trait` does not live long enough
--> src/main.rs:34:29
|
34 | println!("Names: {:?}", names_trait.names());
| ^^^^^^^^^^^ borrowed value does not live long enough
35 | }
| -
| |
| `names_trait` dropped here while still borrowed
| borrow might be used here, when `names_trait` is dropped and runs the destructor for type `impl Names<'_>`
A general rule of thumb when it comes to using lifetimes in Rust is that if you don't know what you're doing, let the compiler infer the correct lifetimes for you. Once you get more experience, you'll learn when you actually need to use explicit lifetime annotations, but your example is not one of those situations. I was able make it compile by removing all the unnecessary lifetime annotations:
playground
To determine which lifetime annotations were unnecessary, I started by removing all of them and then only added lifetime annotations back to the areas where the compiler specifically asked me to.