简体   繁体   中英

Rust lifetime confusion with custom clone function

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

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 it 1 .

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

Playground


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 , ie 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 .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM