这个问题似乎暗示它只是一个实现细节(memcpy vs ??),但我找不到任何关于区别的明确描述。
当前回答
就像这里写的。
复制是隐式发生的,例如作为赋值y = x的一部分。Copy的行为是不可重载的;它总是一个简单的位拷贝。
克隆是一个显式操作,x.clone()。Clone的实现可以提供安全复制值所需的任何特定于类型的行为。例如,Clone For String的实现需要在堆中复制指向字符串的缓冲区。简单的按位复制String值只会复制指针,导致一行中出现double free。因此,字符串是克隆而不是复制。
克隆是复制的一个超特性,所以任何是复制也必须实现克隆。如果一个类型是Copy,那么它的Clone实现只需要返回*self
其他回答
我觉得这个解释很有帮助:
在Rust中,一些简单的类型是“隐式可复制的”,当你分配它们或将它们作为参数传递时,接收者将获得一个副本,原始值保留在适当的位置。对于其他类型,必须通过实现Clone特征并调用Clone()方法显式地进行复制。
Clone特性定义了显式创建对象T的深度副本的能力。当我们为类型T调用Clone时,它会执行创建新T所需的所有任意复杂操作。
rust中的Copy特性定义了隐式复制对象的能力。Copy行为不可重载。它总是一个简单的位拷贝。这适用于具有固定大小且完全存储在堆栈上的类型。
参考:https://intmain.co/difference-between-copy-and-clone-trait-in-rust
就像这里写的。
复制是隐式发生的,例如作为赋值y = x的一部分。Copy的行为是不可重载的;它总是一个简单的位拷贝。
克隆是一个显式操作,x.clone()。Clone的实现可以提供安全复制值所需的任何特定于类型的行为。例如,Clone For String的实现需要在堆中复制指向字符串的缓冲区。简单的按位复制String值只会复制指针,导致一行中出现double free。因此,字符串是克隆而不是复制。
克隆是复制的一个超特性,所以任何是复制也必须实现克隆。如果一个类型是Copy,那么它的Clone实现只需要返回*self
正如其他答案所涵盖的:
复制是隐式的、廉价的,并且不能重新实现(memcpy)。 克隆是显式的,可能是昂贵的,并且可以任意地重新实现。
在复制与克隆的讨论中,有时会忽略的是,它还会影响编译器如何使用移动和自动复制。例如:
#[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();。
这可能会引发一个问题:如何强制移动实现Copy特征的类型?
简单的回答:你不能/没有道理。
Clone是为任意复制而设计的:类型T的Clone实现可以执行创建新T所需的任意复杂操作。它是一个正常的trait(除了在前奏中),因此需要像正常trait一样使用,包括方法调用等。
Copy特征表示可以通过memcpy安全地复制的值:像重赋和按值传递参数给函数这样的事情总是memcpy,因此对于Copy类型,编译器理解它不需要考虑这些移动。
主要的区别是克隆是显性的。隐式符号表示非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.
顺便说一下,每个拷贝类型也要求是克隆。然而,他们不需要做同样的事情!对于您自己的类型,.clone()可以是您选择的任意方法,而隐式复制总是会触发memcpy,而不是clone(&self)实现。
推荐文章
- Rust中的默认函数参数
- 从源代码构建奇偶校验后,货物构建以“阻塞等待注册表索引上的文件锁定”挂起
- 复制和克隆的区别是什么?
- 如何将字节(u8)的矢量转换为字符串?
- 为什么不鼓励接受字符串(&String), Vec (&Vec)或盒子(&Box)作为函数参数的引用?
- 问号运算符是关于什么的?
- 字符串向量上的连接运算符等价于什么?
- Rust程序如何从它的Cargo包中访问元数据?
- 为什么在具有240个或更多元素的数组上循环时会有很大的性能影响?
- 为什么Rust中需要显式生命期?
- Rust 1.x中读写文件的实际方式是什么?
- 如何从同一项目的另一个文件中包含模块?
- 我如何创建一个全局的,可变的单例?
- 多行字符串文字的语法是什么?
- Rust的自动解引用规则是什么?