装箱特征如何影响传递给它的参数的生命周期? (有一个非常具体的例子)

问题描述 投票:0回答:1

这是一个非常简单但具体的示例,它会产生我无法理解的编译错误:

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>
    来编译它)
rust traits lifetime boxing
1个回答
0
投票

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
,如果需要的话它可以永远存在。

© www.soinside.com 2019 - 2024. All rights reserved.