为什么我不能在解构变量后调用方法但是如果直接访问该字段我可以吗?

Ear*_*ine 2 pattern-matching lifetime rust

以下没有编译:

use std::any::Any;

pub trait CloneBox: Any {
    fn clone_box(&self) -> Box<dyn CloneBox>;
}

impl<T> CloneBox for T
where
    T: Any + Clone,
{
    fn clone_box(&self) -> Box<dyn CloneBox> {
        Box::new(self.clone())
    }
}

struct Foo(Box<dyn CloneBox>);

impl Clone for Foo {
    fn clone(&self) -> Self {
        let Foo(b) = self;
        Foo(b.clone_box())
    }
}
Run Code Online (Sandbox Code Playgroud)

错误信息:

error[E0495]: cannot infer an appropriate lifetime for pattern due to conflicting requirements
  --> src/lib.rs:20:17
   |
20 |         let Foo(b) = self;
   |                 ^
   |
note: first, the lifetime cannot outlive the anonymous lifetime #1 defined on the method body at 19:5...
  --> src/lib.rs:19:5
   |
19 | /     fn clone(&self) -> Self {
20 | |         let Foo(b) = self;
21 | |         Foo(b.clone_box())
22 | |     }
   | |_____^
note: ...so that reference does not outlive borrowed content
  --> src/lib.rs:20:17
   |
20 |         let Foo(b) = self;
   |                 ^
   = note: but, the lifetime must be valid for the static lifetime...
note: ...so that the type `&std::boxed::Box<dyn CloneBox>` will meet its required lifetime bounds
  --> src/lib.rs:21:15
   |
21 |         Foo(b.clone_box())
   |  
Run Code Online (Sandbox Code Playgroud)

但是,如果在更改代码clone()Foo(b.clone_box())Foo(self.0.clone_box()),它编译没有问题.理论上,字段访问应该与模式匹配相同,但为什么模式匹配会产生生命周期问题?

在我的实际代码中,数据是枚举,而不是结构,因此模式匹配是唯一的选择.

She*_*ter 5

TL; DR:在调用方法之前取消引用该值:

Foo((*b).clone_box())
Run Code Online (Sandbox Code Playgroud)

let Foo(b) = self,类型b&Box<(dyn CloneBox + 'static)>.方法调用是有效的

Foo(<&Box<dyn CloneBox + 'static> as CloneBox>::clone_box(&b))
Run Code Online (Sandbox Code Playgroud)

Box<dyn CloneBox + 'static>由于本地引用,此值无法转换为特征对象.有趣的是,我相信如果编译器允许的话,这将是递归使用全局实现.

使用self.0.clone_box(),方法调用有效:

Foo(<dyn CloneBox as CloneBox>::clone_box(&**b)
Run Code Online (Sandbox Code Playgroud)

我们可以把它写成Foo((&**b).clone_box())显式,但由于没有中间实现,Foo((*b).clone_box())就足够了.

也可以看看: