Copy和Clone有什么区别?

use*_*234 103 rust

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

huo*_*uon 100

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

Copy特征表示可以通过安全地重复值memcpy:之类的东西调动和价值传递的参数传递给函数总是memcpys和因此对于Copy类型,编译明白它并不需要考虑的一个举动.

  • `Clone`打开*可能性*类型可能做深或浅拷贝:"任意复杂". (6认同)
  • 我可以理解为"Clone"是一个深层拷贝,而"Copy"是影子拷贝吗? (4认同)
  • 令人着迷的是,我认为“复制”只是允许隐含“克隆”特征。我将把参考文献留在这里,因为我可能不是唯一一个感到困惑的人。现在手册中已经回答了这个确切的问题(可能不是在提出这个问题时):“复制是隐式发生的,例如作为赋值 y = x 的一部分。复制的行为不可重载;它始终是一个简单的位-明智的副本。” https://doc.rust-lang.org/std/marker/trait.Copy.html#whats-the-difference- Between-copy-and-clone (2认同)

mdu*_*dup 69

主要区别在于克隆是明确的.隐式表示法意味着移动非Copy类型.

// 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.
Run Code Online (Sandbox Code Playgroud)

顺便说一句,每种Copy类型也是必需的Clone.但是,他们不需要做同样的事情!对于您自己的类型,.clone()可以是您选择的任意方法,而隐式复制将始终触发a memcpy,而不是clone(&self)实现.

  • 凉爽的!这解决了我关于克隆特征是否提供隐式复制的第二个问题。事实证明这个问题和这个问题比我想象的更相关。谢谢! (2认同)
  • 你不能,也不能,因为 `Copy` 旨在为“廉价”类型实现,例如示例中的 `u8`。如果您编写了一个相当重量级的类型,您认为移动比复制更有效,请将其_not_ impl `Copy`。请注意,在 u8 的情况下,您不可能更有效地移动,因为在引擎盖下它可能至少需要一个指针副本——这已经和 u8 副本一样昂贵,所以为什么要麻烦。 (2认同)

blu*_*e10 24

正如其他答案所涵盖的那样:

  • Copy 是隐式的、廉价的,并且不能重新实现 (memcpy)。
  • Clone 是明确的,可能很昂贵,并且可能会任意重新实现。

有时在讨论Copyvs 时遗漏的Clone是它也会影响编译器如何使用移动与自动副本。例如:

#[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);
}
Run Code Online (Sandbox Code Playgroud)

PointCloneAndCopy由于隐式复制,第一个示例 ( ) 在这里工作正常,但第二个示例 ( PointCloneOnly) 在移动后使用会出错:

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
Run Code Online (Sandbox Code Playgroud)

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

这可能会引发一个问题,即如何强制实现 Copy trait 的类型的移动?. 简短的回答:你不能/没有意义。


mdm*_*ndo 10

正如这里所写。

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

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

Clone是一个超特质Copy,所以所有的事情Copy也必须实施Clone。如果一个类型是Copy那么它的Clone实现只需要返回*self