下面是一个非常简单但具体的例子,它产生了一个我无法理解的编译错误:
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
的生存时间不够长,请参阅标记为“here”的行。
我无法理解 Package 器是如何碰巧改变路径被借用的方式的。
编辑
正如@Jmb在下面指出的,这与Path
无关,简单的&str
也会出现同样的问题,例如:
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
}
}
2条答案
按热度按时间kb5ga3dv1#
path
在某个生存期'a
中具有类型&'a Path
,该生存期仅对单个循环迭代有效(直到entry
被丢弃)。当被 Package 在 Package 器中时,
the_impl
具有MyWrapper<T>
类型,用于某种推断类型T
。因为你调用了
the_impl.my_func (path)
,编译器推断T == &'a Path
,所以the_impl
的类型是MyWrapper<&'a Path>
,它不能存在超过'a
的生存期。因此,由于the_impl
的错误需要存在于整个循环中。当你没有 Package
the_impl
时,它有类型MyImpl
,它为所有的生存期'b
* 实现MyTrait<&'b Path>
*,包括比the_impl
的生存期短的生存期(它们只需要足够长,就可以调用my_func
)。因此编译器可以使用MyTrait<&'a Path>
实现,而不会影响the_impl
的生存期。这里的
Path
类型没有什么特别之处,但您的&str
实现可能有。我怀疑在后一种情况下,您最终会得到&'static str
,如果需要,它可以永远存在。k2arahey2#
虽然前面的答案和评论在这个特定的情况下提供了关于寿命推断的非常有用的见解,但是它们并没有带来实际的解决方案。
我终于找到了下面的一个。首先让我们简化一下问题,现在使用
String
:当然,它失败的原因和以前完全一样:
然而,如果改变
MyTrait
,使T
在my_func
的签名中通过引用传递,并相应地调整其余部分:然后
foobar()
函数可以保持不变,但现在它编译。而且,正如@kmdreko在下面所说的,它也适用于
str
或其他非大小类型,如Path
,但需要进行以下修改:然后,回到最初的用例,下面的代码现在可以按预期工作:
底线
请参阅@Jmb的回答和相关评论,了解有关第一个解决方案无法编译的原因的一些解释。