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

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"的行.

我不明白包装器是如何碰巧改变路径被borrow 的方式的.

EDIT

正如@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
    }
}

EDIT2

对于任何遇到这个问题的人,有一个可行的解决方案,可以按照我的回答中所描述的那样修改特征.

推荐答案

尽管前面的回答和 comments 提供了关于这种特殊情况下的终身推断的非常有用的见解,但它们并没有提供实际的解决方案.

我终于找到了下面这一条.首先让我们把问题简单化一点,暂时使用String:

trait MyTrait<T> { fn my_func(&self, t: T); }

struct MyImpl {}

impl MyTrait<&String> for MyImpl {
    fn my_func(&self, t: &String) { println!("{}", t) }
}

struct MyWrapper<T> { inner: Box<dyn MyTrait<T>> }

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 { inner: Box::new(the_impl) };
    {
        let s = String::from("blah");
        the_impl.my_func(&s); // <== error: 's' does not live long enough
    }
}

但是,如果更改MyTrait,则Tmy_func的签名中通过引用传递,并相应地调整其余部分:

trait MyTrait<T> { fn my_func(&self, t: &T); } // <== main change here

struct MyImpl {}

impl MyTrait<String> for MyImpl {
    fn my_func(&self, t: &String) { println!("{}", t) } // <== note the actual signature hasn't changed
}

struct MyWrapper<T> { inner: Box<dyn MyTrait<T>> }

impl<T> MyTrait<T> for MyWrapper<T> {
    fn my_func(&self, t: &T) { self.inner.my_func(t); }
}

那么foobar()函数可以保持不变,but now it compiles.

而且,正如@kmdreko下面所说的,它也将适用于str或或其他非大小的类型,如Path,但进行了以下修改:

trait MyTrait<T: ?Sized> { fn my_func(&self, t: &T); }

struct MyWrapper<T: ?Sized> { inner: Box<dyn MyTrait<T>> }

impl<T: ?Sized> MyTrait<T> for MyWrapper<T> {
    fn my_func(&self, t: &T) { self.inner.my_func(t); }
}

然后,回到最初的用例,下面的代码现在可以按预期工作:

impl MyTrait<Path> for MyImpl {
      fn my_func(&self, t: &Path) { println!("{:?}", t) }
}

fn foobar_with_path_in_a_loop() {
    let the_impl = MyImpl{};        
    let the_impl = MyWrapper { inner: Box::new(the_impl) };
    
    for entry in walkdir::WalkDir::new("blah") {
        let entry = entry.unwrap();
        let path = entry.path();
        the_impl.my_func(path);
    }
}

Bottomline

有关第一个解决方案无法编译的原因,请参阅@jmb的答案和相关注释.

Rust相关问答推荐

如何为utoipa中的可选查询参数生成OpenAPI模式?

这个规则关于或模式到底是什么意思?如果表达片段的类型与p_i|q_i...&q;不一致,就会形成

如何循环遍历0..V.len()-1何时v可能为空?

如果包名称与bin名称相同,并且main.ars位于工作区的同一 crate 中,则无法添加对lib.ars的依赖

在文件链实施中绕过borrow 判断器

获取已知数量的输入

减少指示ProgressBar在Rust中的开销

Rust 中什么时候可以返回函数生成的字符串切片&str?

为什么 vec![Vec::with_capacity(n)] 为子向量创建 0 容量?

为什么 `Deref` 没有在 `Cell` 上实现?

为什么特征默认没有调整大小?

Rust proc_macro 和 syn:解析空格

为什么将易错函数的泛型结果作为泛型参数传递 infer ()?不应该是暧昧的吗?

Rust并发读写引起的死锁问题

`tokio::pin` 如何改变变量的类型?

判断对象是 PyDatetime 还是 Pydate 的实例?

为什么传递 option.as_ref 的行为不同于使用匹配块并将内部映射到 ref 自己?

使用部分键从 Hashmap 中检索值

如何在没有 `make_contiguous()` 的情况下对 VecDeque 进行排序或反转?

如何在 Rust 的内置函数上实现特征?