复制和克隆有什么区别?

这个问题 似乎暗示它只是一个实现细节(memcpy vs? ? ?),但我找不到任何明确的描述,差异。

54064 次浏览

主要的区别是克隆是显性的。隐式符号表示非-Copy类型的move。

// u8 implements Copy
let x: u8 = 123;
let y = x;
// x can still be used
println!("x={}, y={}", x, y);


// Vec<u8> implements Clone, but not Copy
let v: Vec<u8> = vec![1, 2, 3];
let w = v.clone();
//let w = v // This would *move* the value, rendering v unusable.

顺便说一下,每个Copy类型也必须是Clone。然而,他们不需要做同样的事情!对于你自己的类型,.clone()可以是你选择的任意方法,而隐式复制总是会触发memcpy,而不是clone(&self)实现。

Clone是为任意复制而设计的:类型TClone实现可以执行创建新T所需的任意复杂操作。它是一个正常的trait(除了在前奏中),因此需要像正常的trait一样使用,与方法调用等一起使用。

Copy特征表示可以通过memcpy安全地复制的值:像重赋和按值传递参数给函数这样的事情总是memcpy,因此对于Copy类型,编译器理解它不需要考虑那些这一举动

正如其他答案所涵盖的:

  • Copy是隐式的,廉价的,不能重新实现(memcpy)。
  • Clone是显式的,可能是昂贵的,并且可以任意地重新实现。

在讨论CopyClone时,有时会遗漏的是,它还会影响编译器如何使用移动和自动复制。例如:

#[derive(Debug, Clone, Copy)]
pub struct PointCloneAndCopy {
pub x: f64,
}


#[derive(Debug, Clone)]
pub struct PointCloneOnly {
pub x: f64,
}


fn test_copy_and_clone() {
let p1 = PointCloneAndCopy { x: 0. };
let p2 = p1; // because type has `Copy`, it gets copied automatically.
println!("{:?} {:?}", p1, p2);
}


fn test_clone_only() {
let p1 = PointCloneOnly { x: 0. };
let p2 = p1; // because type has no `Copy`, this is a move instead.
println!("{:?} {:?}", p1, p2);
}

(生锈的操场)

第一个例子(PointCloneAndCopy)在这里工作得很好,因为有隐式复制,但第二个例子(PointCloneOnly)在move后使用时会出错:

error[E0382]: borrow of moved value: `p1`
--> src/lib.rs:20:27
|
18 |     let p1 = PointCloneOnly { x: 0. };
|         -- move occurs because `p1` has type `PointCloneOnly`, which does not implement the `Copy` trait
19 |     let p2 = p1;
|              -- value moved here
20 |     println!("{:?} {:?}", p1, p2);
|                           ^^ value borrowed here after move

为了避免隐式移动,可以显式调用let p2 = p1.clone();

这可能会引发如何强制实现复制特征的类型的移动?的问题。

简单的回答:你不能/没有道理。

在这里所写。

复制隐式发生,例如作为赋值y = x的一部分。Copy的行为是不可重载的;它总是一个简单的位拷贝。

克隆是一个显式动作,x.clone()Clone的实现可以提供安全复制值所需的任何特定于类型的行为。例如,StringClone的实现需要复制堆中的指向字符串缓冲区。String值的简单逐位复制只会复制指针,导致一行中出现double free。因此,StringClone而不是Copy

CloneCopy的超特征,所以所有属于Copy的东西也必须实现Clone。如果类型是Copy,那么它的Clone实现只需要返回*self