这是一个非常简单但具体的示例,它会产生我无法理解的编译错误:
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);
}
}
当标记(*)的行被注释时,一切都很好。但是,如果未注释,编译器会抱怨
entry
生存时间不够长,请参阅标记为“此处”的行。
我尝试了很多关于生命周期参数、
AsRef
等的技巧,但没有成功。该问题似乎与 this question 有关,但添加 static
生命周期也不起作用。
我不明白的是:
Path
在这里发挥作用吗? (因为我设法通过 MyImpl
实现 MyTrait<&str>
来编译它)path
在某个生命周期内具有类型 &'a Path
'a
,仅对单个循环迭代有效(直到 entry
被丢弃)。
当包裹在包装纸中时,
the_impl
具有类型MyWrapper<T>
,用于某些推断类型T
。
由于您调用
the_impl.my_func (path)
,编译器会推断出 T == &'a Path
,因此 the_impl
具有类型 MyWrapper<&'a Path>
,该类型的存在时间不能超过 'a
的生命周期。因此,由于 the_impl
需要在整个循环中存在错误。
当您不包装
the_impl
时,它具有类型 MyImpl
,它为所有生命周期 MyTrait<&'b Path>
实现 'b
,包括比 the_impl
生命周期短的生命周期。因此编译器可以使用 MyTrait<&'a Path>
实现,而不影响 the_impl
的生命周期。
这里的
Path
类型没有什么特别的,但你的 &str
实现可能有特殊之处。我怀疑在后一种情况下你最终会得到 &'static str
,如果需要的话它可以永远存在。