Reputation: 603
I think there is a subtle issue with what I'm trying to do here but I can't quite figure out why. I am attempting to clone a Box type (I know the type inside) but I think the lifetime is being propagated out somehow.
struct Thing
{
internal:Box<dyn std::any::Any>
}
impl Thing
{
fn new<T:'static>(u:usize) -> Self
{
return Self
{
internal:Box::new(u)
}
}
fn clone_func<T:'static>(&self) -> Self
{
return Self
{
internal:Box::new(self.internal.downcast_ref::<T>().unwrap().clone())
}
}
}
pub fn main()
{
let a = Thing::new::<usize>(12usize);
let b = a.clone_func::<usize>();
}
Error
error[E0759]: `self` has an anonymous lifetime `'_` but it needs to satisfy a `'static` lifetime requirement
--> <source>:19:45
|
15 | fn clone_func<T:'static>(&self) -> Self
| ----- this data with an anonymous lifetime `'_`...
...
19 | internal:Box::new(self.internal.downcast_ref::<T>().unwrap().clone())
| -----------------------^^^^^^^^^^^^------------------------- ...is captured and required to live as long as `'static` here
error: aborting due to previous error
Upvotes: 1
Views: 516
Reputation: 154876
The problem is that you didn't request T
to be Clone
, so when you called self.internal.downcast_ref::<T>().unwrap().clone()
, you actually cloned the reference, and tried to box it1.
Boxing &T
works as far as the types are concerned (because it's a Box<dyn Any>
), but it fails borrow checking. While T
is guaranteed not to contain references to non-static data, the &T
refers to the data inside &self
which is not 'static
, but has the anonymous lifetime of &self
. This is actually pointed out by the compiler, but the error doesn't make sense without context.
Simply changing the trait bound to T: Clone + 'static
makes the example compile:
fn clone_func<T: Clone + 'static>(&self) -> Self {
return Self {
internal: Box::new(self.internal.downcast_ref::<T>().unwrap().clone()),
};
}
1
A shared reference is Clone
and Copy
because once you have one, you're allowed to create more references to the same data. Normally, given a foo: &T
and a T: Clone
, foo.clone()
will resolve to T::clone(foo)
, which returns a T
as expected. But if T
isn't Clone
, foo.clone()
resolves to <&T>::clone(&foo)
, which returns another &T
referring to the same T
value as foo
, i.e. it "clones" foo
itself rather than the intended *foo
.
For example, in this snippet, the type of b.clone()
is &X
, not X
(playground):
//#[derive(Clone)]
struct X;
fn main() {
let a = X;
let b = &a;
let () = b.clone(); // note type of b.clone() is &X, not X
}
If you uncomment #[derive(Clone)]
, the type of b.clone()
becomes the expected X
.
Upvotes: 2