Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

References to trait objects are not cloneable

Tags:

rust

traits

Why references to trait objects are not cloneable? This code compiles:

struct Test;

fn clone_vec<'a>(v: Vec<&'a Test>) -> Vec<&'a Test> {
    v.clone()
}

fn main() {
}

This one doesn't:

trait Test {
    fn do_smt(&self);
}

fn clone_vec<'a>(v: Vec<&'a Test>) -> Vec<&'a Test> {
    v.clone()
}

fn main() {
}

Error:

main3.rs:7:5: 7:14 error: failed to find an implementation of trait std::clone::Clone for &'a Test<no-bounds>
main3.rs:7     v.clone()
               ^~~~~~~~~

However, Clone trait is implemented for any kind of reference, as far as I can see:

impl<'a, T> Clone for &'a T {
    /// Return a shallow copy of the reference.
    #[inline]
    fn clone(&self) -> &'a T { *self }
}

I just don't see why &'a Test where Test is a trait is not cloneable. It's just a pointer after all. This restriction prohibits, for example, going from &[&'a SomeTrait] to Vec<&'a SomeTrait>, which looks like an obvious conversion, or cloning a Vec<&'a SomeTrait>, as in the example.

This is very strange provided that I can implement clone_vec() myself, without Clone:

fn clone_vec<'a>(v: Vec<&'a Test>) -> Vec<&'a Test> {
    let mut result = Vec::new();
    for &e in v.iter() {
        result.push(e);
    }
    result
}
like image 400
Vladimir Matveev Avatar asked May 02 '14 11:05

Vladimir Matveev


1 Answers

Clone is a normal library trait, and requires normal (library) implementations, for all types. For example, Clone is implemented for &T right here, in the form:

impl<'a, T> Clone for &'a T {
    /// Return a shallow copy of the reference.
    #[inline]
    fn clone(&self) -> &'a T { *self }
}

Hence, everything of the form &T is Cloneable... where T a concrete type. And that's the clincher: &Trait is not (yet) a type of the form &T with T = Trait (but rather an "atomic"/primitive type that can't be separated into parts), so it is not covered by that impl.

We require dynamically sized types (DST) for the compiler to be able to reason about passing just plain old Trait around as a generic parameter (Nick Cameron is actually hard at work at some parts of the DST implementation, so this will hopefully happen soon).

You can, however, manually implement Clone for your traits of interest, e.g. the following works well:

trait Foo {}

impl<'a> Clone for &'a Foo {
    fn clone(&self) -> &'a Foo {
        *self
    }
}

However, it only works for traits defined in your current crate, or else the compiler has concerns about coherence (e.g. changing Foo to Eq in the impl above causes error: cannot provide an extension implementation where both trait and type are not defined in this crate).

like image 108
huon Avatar answered Oct 24 '22 16:10

huon