2

The following didn't compile:

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())
    }
}

Error message:

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())
   |  

However if change the code in clone() from Foo(b.clone_box()) to Foo(self.0.clone_box()), it compiles without problem. In theory, field access should be the same as pattern matching, but why does pattern matching have lifetime issues?

In my real code, the data is in an enum, not a struct, so pattern matching is the only option.

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
Earth Engine
  • 10,048
  • 5
  • 48
  • 78

1 Answers1

5

TL;DR: Dereference the value before calling the method:

Foo((*b).clone_box())

With let Foo(b) = self, the type of b is &Box<(dyn CloneBox + 'static)>. The method call is effectively

Foo(<&Box<dyn CloneBox + 'static> as CloneBox>::clone_box(&b))

This value cannot be made into the trait object Box<dyn CloneBox + 'static> because of the local reference. Amusingly, I believe this would be recursively using the blanket implementation if the compiler allowed it.

With self.0.clone_box(), the method call is effectively:

Foo(<dyn CloneBox as CloneBox>::clone_box(&**b)

We could write this as Foo((&**b).clone_box()) to be explicit, but since there's no intermediate implementations, Foo((*b).clone_box()) is sufficient.

See also:

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366