// 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.
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
5条答案
按热度按时间carvr3hs1#
Clone
设计用于任意复制:类型T
的Clone
实现可以执行创建新T
所需的任意复杂操作。它是一个普通trait(而不是在序言中),因此需要像普通trait一样使用方法调用等。Copy
trait表示可以通过memcpy
安全复制的值:像重新分配和按值传递参数给函数这样的事情总是memcpy
s,所以对于Copy
类型,编译器知道它不需要考虑那些a move。8cdiaqws2#
主要的区别是克隆是显式的,隐式表示法意味着非
Copy
类型的移动。顺便说一下,每个
Copy
类型也需要是Clone
,但是,它们不需要做同样的事情!对于您自己的类型,.clone()
可以是您选择的任意方法,而隐式复制总是触发memcpy
,而不是clone(&self)
实现。bfnvny8b3#
如其他答复所述:
Copy
是隐式的、廉价的,并且不能被重新实现(memcpy)。Clone
是显式,可能是昂贵的,且可以被任意地重新实现。在讨论
Copy
与Clone
时,有时候忽略了编译器如何使用移动与自动复制。例如:(Rust Playground)
由于隐式复制,第一个示例(
PointCloneAndCopy
)在这里运行良好,但第二个示例(PointCloneOnly
)会因在移动后使用而出错:为了避免隐式移动,我们可以显式调用
let p2 = p1.clone();
。这可能会引起how to force a move of a type which implements the Copy trait?的问题。
fjaof16o4#
就像这里写的。
复制是隐式发生的,例如作为赋值
y = x
的一部分。Copy
的行为是不可重载的;它总是简单的逐位复制。克隆是一个显式操作
x.clone()
。Clone
的实现可以提供安全复制值所需的任何类型特定的行为。例如,String
的Clone
实现需要复制堆中指向的字符串缓冲区。String
值的简单按位复制将仅复制指针,从而导致线上出现双释放。因此,String
是Clone
,而不是Copy
。Clone
是Copy
的超特性,所以Copy
的所有东西都必须实现Clone
,如果类型是Copy
,那么它的Clone
实现只需要返回*self
xbp102n05#
我发现这个解释很有帮助:
在Rust中,一些简单类型是"隐式可复制的",当你赋值它们或将它们作为参数传递时,接收方将得到一个副本,原始值保留在原处。对于其他类型,必须通过实现
Clone
trait和调用clone()
方法显式地进行复制。Clone
trait定义了显式创建对象T的深层副本的能力。当我们为类型T调用Clone
时,它会执行创建新T所需的所有任意复杂的操作。rust中的
Copy
trait定义了隐式复制对象的能力。Copy
行为是不可重载的。它总是简单的按位复制。这适用于具有固定大小并且完全存储在堆栈上的类型。参考:https://intmain.co/difference-between-copy-and-clone-trait-in-rust