Mut reference clone

What is the expected behavior of calling clone() on &mut T? Is it defined as calling T.clone() ? I tried in Rust playground, it seems calling T.clone(), but the doc seems to say something different.

playground test:

fn dup(v: &mut Vec<u8>) -> Vec<u8> {
    v.clone()
}

fn consume(v: Vec<u8>) {
    println!("consuming v1: {:?}", v);
}

fn main() {
    let mut v1 = vec![1, 2];
    let v2 = dup(&mut v1);  
    consume(v1);
    println!("v2: {:?}", v2);
}

(Playground)

It's the type coercion which allows to call methods that takes &T on &mut T.

1 Like

Does it mean that clone() call works same with &mut T, &T and T ?
If that's the case, the following statements in the doc are confusing:

The following traits are implemented for all &T , regardless of the type of its referent:

  • Clone (Note that this will not defer to T 's Clone implementation if it exists!)

&mut T references get all of the above except Copy and Clone (to prevent creating multiple simultaneous mutable borrows),

I would’ve thought it is actually automatic dereferencing.

According to the reference when a &mut Vec<u8> is encoutered, the receiver types &mut Vec<u8>, &&mut Vec<u8>, &mut &mut Vec<u8>, Vec<u8>, &Vec<u8>, &mut Vec<u8>, [T], &[T], &mut [T] are checked in this order, because of the Deref implementations of &mut T and Vec.

Then the first one of those types is used that can offer a clone method. More precisely, when we want to consider clone from Clone, that one takes its argument by-reference, so to successfully apply the Clone trait, the receiver type must be of the form &T for some T: Clone.

Let’s start trying:

  • &mut Vec<u8> is not of the form &T.
  • &&mut Vec<u8> is of the form &T for T = &mut Vec<u8>, but &mut Vec<u8> does not implement Clone.
  • &mut &mut Vec<u8> is not of the form &T.
  • Vec<u8> is not of the form &T.
  • &Vec<u8> is of the form &T for T = Vec<u8>, and Vec<u8> does implement clone

So the call v.clone() for v: &mut Vec<u8> becomes <Vec<u8>>::clone(<&mut Vec<u8>>::deref(&v))

For a sanity check, this does compile:

fn dup(v: &mut Vec<u8>) -> Vec<u8> {
    use std::ops::Deref;
    <Vec<u8>>::clone(<&mut Vec<u8>>::deref(&v))
}
3 Likes

Yeah, you can try to make sense of this by following my above explanation (previous comment). Perhaps you can try to apply the same logic to find out why in clone_ref1 and clone_ref2 you need to add the & to make it compile.

fn clone_ref<T>(x: &T) -> &T {
    x.clone()
}
fn clone_ref1(x: &u8) -> &u8 {
    // x.clone() does not compile here
    (&x).clone()
}
fn clone_ref2<T: Clone>(x: &T) -> &T {
    // x.clone() does not compile here
    (&x).clone()
}
1 Like

The dot operator is a bit magical

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.