没有为 Moved 值调用克隆?

Clone not invoked for Moved value?

我想了解 Copy 如何与 Rust 中的移动语义交互。我希望这个程序能够克隆对象,但事实并非如此。我有 rust 1.0.0-beta.

#[derive(Debug)]                                  
struct X {
  y : i32,
}

impl Clone for X {
  fn clone(&self) -> X { 
    println!("clone");
    X { y: 4 }
  } 
}

impl Copy for X { }  

fn doit(x : X) {     
  println!("doit {:?}", x);
}

fn main() { 
  let z = X { y: 5 };    
  println!("main {:?}", z);
  doit(z);        
  println!("main {:?}", z);
}

这是我的困惑:如果 X 不是 "Copy",doit 将取得对象 z 的所有权并将其丢弃在范围的末尾。然后, main 中的第二个 println 会抱怨,因为 z 被移动了。美好的。但是,现在我已将 X 标记为 Copy 并提供了一个克隆方法。我预计克隆方法将用于为 doit 提供它自己的 z 副本,从而允许我在 doit 之后继续使用 z。那不会发生。

我哪里理解错了?

Clone 没什么特别的。这只是一个普通的图书馆特征。你可以自己定义!

因此,.clone() 仅在您明确调用它时使用。复制和移动都与Clone无关。当您调用 doit(z) 时,zCopy 意义上被复制,这意味着在引擎盖下按字节复制。如果你想克隆传递给doit,那么写:

doit(z.clone());

现在 current (2021) documentation 更清楚了

What's the difference between Copy and Clone?

Copies happen implicitly, for example as part of an assignment y = x. The behavior of Copy is not overloadable; it is always a simple bit-wise copy.

Cloning is an explicit action, x.clone(). The implementation of Clone can provide any type-specific behavior necessary to duplicate values safely.
For example, the implementation of Clone for String needs to copy the pointed-to string buffer in the heap.
A simple bitwise copy of String values would merely copy the pointer, leading to a double free down the line. For this reason, String is Clone but not Copy.

Clone is a supertrait of Copy, so everything which is Copy must also implement Clone.
If a type is Copy then its Clone implementation only needs to return *self

struct MyStruct;

impl Copy for MyStruct { }

impl Clone for MyStruct {
    fn clone(&self) -> MyStruct {
        *self
    }
}

另请参阅 2020 年文章“Moves, copies and clones in Rust

When a value is moved, Rust does a shallow copy; but what if you want to create a deep copy like in C++?
To allow that, a type must first implement the Clone trait.
Then to make a deep copy, client code should call the clone method:

let v: Vec<i32> = Vec::new();
let v1 = v.clone();//ok since Vec implements Clone
println!("v's length is {}", v.len());//ok

This results in the following memory layout after the clone call: Due to deep copying, both v and v1 are free to independently drop their heap buffers.

Note

The clone method doesn't always create a deep copy.

Types are free to implement clone any way they want, but semantically it should be close enough to the meaning of duplicating an object.
For example, Rc and Arc increment a reference count instead.