rustclone

What different between variable ref clone and variable deref clone?


I run this code to proof the the difference, All address are different.

#[derive(Clone, Debug)]
#[allow(unused)]
struct Settings {
    volume: u16,
}

fn main() {
    let settings = &Settings { volume: 10 };

    let a = (*settings).clone(); // (1)
    let b = settings.clone(); // (2)

    println!("address of 'settings' point to: {:p}", settings);
    println!("address of 'a': {:p}", &a);
    println!("address of 'b': {:p}", &b);
}

Output:

address of 'settings' point to: 0x55e784c480a8
address of 'a': 0x7ffebad638b4
address of 'b': 0x7ffebad638b6

I also read the Trait clone on standard document. They said:

Calling clone always produces a new value. However, for types that are references to other data (such as smart pointers or references), the new value may still point to the same underlying data, rather than duplicating it. See Clone::clone for more details.

So, It might not deep clone variable if we use reference clone?


Solution

  • Ultimately it's up to individual types to implement Clone, but deriving Clone will always do a “deep” clone — meaning it will clone the fields using their implementation, which might not be deep as in the case of e.g. Rc.

    The question is what exactly is being cloned. Since the signature is clone(&self) -> Self,

    So, for instance, cloning &&U will return &U. Here is perhaps an instructive example:

    #[derive(Clone)]
    struct S<'a> {
        x: &'a u16,
    }
    
    fn main() {
        let settings = &S { x: &10 };
    
        let a: S = (*settings).clone();
        let b: S = settings.clone();
        let c: &S = (&settings).clone();  // clippy warning: clone on a double reference
    
        println!("address of 'settings' point to: {:p}", settings);
        println!("address of 'a': {:p}, {:p}", &a, a.x);
        println!("address of 'b': {:p}, {:p}", &b, b.x);
        println!("address of 'c': {:p}, {:p}", c, c.x);
    }
    
    address of 'settings' point to: 0x1000b0060
    address of 'a': 0x16fd95d38, 0x1000a3a30
    address of 'b': 0x16fd95d40, 0x1000a3a30
    address of 'c': 0x1000b0060, 0x1000a3a30
    

    Note that settings and c (which are references) point to the same location, as do all the xs, because in both cases the clone of a reference is itself.

    Another thing of note, which I'll mention here even though it's tangential to the question asked, is that auto-deref rules determine what T is when calling clone(). For instance, when T: Clone then if t: T then t.clone() tries to call <T as Clone>::clone(&t) (which returns a T). But when T: !Clone — common cases being str and [U] — then auto-deref doesn't call <T as Clone>::clone(&t) -> T (because it doesn't exist) but rather <&T as Clone>::clone(&&t) -> &T, and so the reference, not the value, is cloned — and indeed it's not possible to “deep clone” a &str because you cannot have a str not behind a reference.