Here is a very simple but specific example that produces a compilation error I cannot understand:
use std::path::Path;
trait MyTrait<T> {
fn my_func(&self, t: T);
}
struct MyImpl {}
impl MyTrait<&Path> for MyImpl {
fn my_func(&self, t: &Path) {
println!("{:?}", t)
}
}
struct MyWrapper<T> {
inner: Box<dyn MyTrait<T>>
}
impl<T> MyWrapper<T> {
pub fn new(inner: Box::<dyn MyTrait<T>> ) -> Self {
Self { inner }
}
}
impl<T> MyTrait<T> for MyWrapper<T> {
fn my_func(&self, t: T) {
self.inner.my_func(t);
}
}
fn foobar() {
let the_impl = MyImpl{};
//let the_impl = MyWrapper::new(Box::new(the_impl)); // (*)
for entry in walkdir::WalkDir::new("blah") {
let entry = entry.unwrap();
let path = entry.path(); // <== here
the_impl.my_func(path);
}
}
When the line marked (*) is commented, everything is fine. However, if uncommented, the compiler complains about entry not living long enough, see the line marked "here".
I fail to understand how the wrapper happens to change the way the path is borrowed.
EDIT
As pointed out by @Jmb below, this has nothing to do with Path, and the same problem arises with a simple &str, for example:
impl MyTrait<&str> for MyImpl {
fn my_func(&self, t: &str) {
println!("{:?}", t)
}
}
fn foobar_str() {
let the_impl = MyImpl{};
let the_impl = MyWrapper::new(Box::new(the_impl));
{
let s = String::from("blah").clone();
the_impl.my_func(&s as &str); // <== same error
}
}
Although the previous answer and comments provide very useful insights about lifetime inferences in this particular case, they don't come with a practical solution.
I finally found out the following one. First let's simplify a bit the problem, using a
Stringfor now:Of course it fails exactly for the same reason as before:
However, if one changes
MyTraitsoTis passed by reference in the signature ofmy_func, and adapts the rest accordingly:Then the
foobar()function can be left unchanged, but now it compiles.And, as stated by @kmdreko below, it will also work for
stror or other non-sized types likePath, with the following modifications:Then, to come back to the initial use case, the following code now works as expected:
Bottomline
See @Jmb's answer and associated comments for some explanations about why the first solution doesn't compile.