这个问题似乎意味着这只是一种实现细节(memcpy
与???),但我找不到任何明确描述差异的内容。
Clone
旨在进行任意复制:类型T
的Clone
实现可以执行创建新T
所需的任意复杂操作。它是一个普通的trait(除了出现在prelude中),因此需要像普通trait一样使用,包括方法调用等。
Copy
trait表示可以通过memcpy
安全复制的值:诸如重新赋值和按值传递参数给函数等操作始终是memcpy
,因此对于Copy
类型,编译器知道它不需要考虑那些移动。
Clone
是深拷贝,而Copy
是浅拷贝吗? - DjvuClone
的作用是打开这个类型可以进行深拷贝或浅拷贝的 可能性:"任意复杂"。 - poolieCopy
只是允许使Clone
特征隐式化的一部分。我会把参考资料留在这里,因为我可能不是唯一一个困惑的人。现在手册中已经回答了这个确切的问题(可能在提问时没有):“复制是隐式发生的,例如作为赋值y = x的一部分。复制的行为不能被重载;它总是一个简单的按位复制。” https://doc.rust-lang.org/std/marker/trait.Copy.html#whats-the-difference-between-copy-and-clone - vincentCopy
类型。// 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)
实现。
y
获取移动的 x
,而不是像您最后注释掉的示例 w = v
中的副本。您该如何指定? - johnbakersCopy
是为“廉价”类型设计的,比如示例中的u8
。如果你编写的是相当重量级的类型,你认为移动比复制更有效率,那就别实现 Copy
。需要注意的是,在u8的情况下,你不可能通过移动来更有效地操作,因为在底层它可能至少涉及指针复制——这已经与u8复制一样昂贵了,所以还有什么必要呢。 - mdupCopy
trait 的存在会影响变量的隐式生命周期范围?如果是,我认为这值得注意。 - Brian Cain如其他回答所述:
Copy
是隐式的、廉价的,不能重新实现(memcpy)。Clone
是显式的,可能很昂贵,并且可以任意重新实现。讨论Copy
与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);
}
第一个例子(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
为了避免隐式移动,我们可以显式调用let p2 = p1.clone();
。
这可能会引发如何强制移动实现Copy trait的类型的问题?
简短回答:你不能 / 没有意义。
Copy
只是在内存中对结构进行了memcpy。这是尽可能“浅”的操作,不应与“深复制”混淆。最便宜的可能不会丢失信息的Clone
基本上必须模拟一个memcpy。也许如果Clone
不复制所有字段,则可以更便宜地实现。 - bluenote10请看这里。
复制是隐式发生的,例如作为赋值的一部分
y = x
。Copy
的行为不能被重载; 它总是一个简单的按位复制。
克隆是显式动作,
x.clone()
。Clone
的实现可以提供任何类型特定的行为以安全地复制值。例如,String
的Clone
实现需要复制堆中指向的字符串缓冲区。对于String
值的简单按位复制只会复制指针,导致下游出现双重释放。因此,String
是Clone
但不是Copy
。
Clone
是Copy
的超级特性,因此所有实现了Copy
的类型也必须实现Clone
。如果一个类型是Copy
,那么其Clone
实现只需要返回*self
在我看来,意图就是你所需要的一切
.clone
,这意味着它已经处理好了Clone
特质定义了显式创建深拷贝的能力。不,拷贝是任意的,因此不一定是深拷贝。请参考被接受的答案。 - undefined
Clone
的内容都在文档页面的顶部。 - CircArgs