Clone_double_ref

Official error example:

let x = vec![1];
    let y = &&x;
    let z = y.clone();
    println!("{:p} {:p}", *y, z); // prints out the same pointer

I encountered the situation:

    #[derive(Debug)]
    struct Team {
        goals_scored: u8,
    }
    let mut vec2 = vec![];
    let team = Team { goals_scored: 1 };
    vec2.push(Some(&team));
    let option: Option<&Team> = vec2[0];
    let x2: &Team = option.unwrap();
    let result2: &Team = x2.clone();   // clone A warning appears
    println!("{:?}=clone A warning appears", result2);

I replaced Some(&team) with Some(&string1), everything else is the same

    let mut vec1 = vec![];
    let string1 = String::from("123");
    vec1.push(Some(&string1));
    let option1: Option<&String> = vec1[0];
    let x1: &String = option1.unwrap();
    let result1: String = x1.clone();  //clone ok
    println!("{}=clone ok", result1);

It compiles fine, although clippy prompts an error, I don't know how this affects anything.

let x2: &Team = option.unwrap();

In this line of code, x2 is not &&Team, what concepts am I missing?

So, this is due to method resolution. The type &Team is not the receiver type for any existing method called "clone", because Team does not implement Clone and there's no other trait or direct impl offering a method with this name either (note that Clone::clone is a &self method, so that a Clone for Foo implementation gives rise to a clone method with receiver type &Foo, not Foo, and it is this receiver type that method resolution is concerned with).

See this reference page for more details on the way the compiler performs method resolution.

Since &Team has no clone method, the compiler keeps searching for more alternative receiver types, as listed in the reference linked above, which can be obtained via implicit automatic referencing and dereferencing. In particular, for any type T of an expression EXP, when resolving a method call EXP.foo(), also the receiver types &T and &mut T are considered, which makes &self and &mut self methods still convenient to call even on owned values. This step is sometimes called automatic referencing. Automatic dereferencing does not come into play in these code examples, it would be a subsequent step of the automatic referencing does not find any suitable receiver type either.

In this case, after &Team, the compiler thus considers &&Team next, and does find a clone implementation (due to &T implementing Copy and Clone genetically for all types T, and the &self receiver type of this Clone::clone implementation is therefore &&T which matches our type at hand, &&Team). The call x2.clone() thus ultimately desugars to Clone::clone(&x2).

And there you have the double reference that Clippy is linting against, &x2 is of type &&Team. That being said, it looks like the lint designers didn't consider this case very well either, as the actual lint message is hard to understand and contains fairly useless automatic suggestions (at least the first suggestion seems to be unaware of the automatic referencing) as "help"

error: using `clone` on a double-reference; this will copy the reference of type `&Team` instead of cloning the inner type
  --> src/main.rs:10:26
   |
10 |     let result2: &Team = x2.clone();   // clone A warning appears
   |                          ^^^^^^^^^^
   |
   = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#clone_double_ref
   = note: `#[deny(clippy::clone_double_ref)]` on by default
help: try dereferencing it
   |
10 |     let result2: &Team = &(*x2).clone();   // clone A warning appears
   |                          ~~~~~~~~~~~~~~
help: or try being explicit if you are sure, that you want to clone a reference
   |
10 |     let result2: &Team = <&Team>::clone(x2);   // clone A warning appears
   |                          ~~~~~~~~~~~~~~~~~~

For the example involving String since String does implement Clone, when resolving x1.clone() the type &String, which is the type of x1, already has a clone method. The same kind of thing happens if you were to add derive(Clone) to Team.

2 Likes

I see. Thank you.

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.