Rust中Copy与Clone的区别

1,238 阅读2分钟

虽然很多人写过Copy与Clone的区别,例如哪个有多了个函数啦,Copy是标准库的特殊例子啦,这些都是从源码和实现上去写的,容易被绕得云里雾里,直到看了《Rust语言圣经(Rust Course)》-所有权,从使用者的角度来说明,才恍然大悟。

这里摘要一下,不再复制粘贴标准库里的文字,而是从使用者经验上去看待:

首先,Copy和Clone都是做同一个事情:拷贝(深或浅)。

区别在于:

Copy:基本类型都实现了Copy

任何基本类型的组合,不需要分配内存或某种形式资源的类型“,即以下的类型的拷贝就默认实现了Copy:

  • 所有整数类型,比如 u32
  • 布尔类型,bool,它的值是 true 和 false
  • 所有浮点数类型,比如 f64
  • 字符类型,char
  • 元组,当且仅当其包含的类型也都是 Copy 的时候。比如,(i32, i32) 是 Copy 的,但 (i32, String) 就不是。
  • 不可变引用 &T ,例如转移所有权中的最后一个例子,但是注意: 可变引用 &mut T 是不可以 Copy的

在使用以上类型的时候,不用担心所有权转移的问题,因为他们都自动做了拷贝,而且操作是非常快的。快是因为他们只是已知长度,只在栈上的数据,所以又叫浅拷贝。

Clone:需要使用者手动调用的拷贝

一些复合型的类型,例如String,有栈上的指针,长度和容易,同时也有堆内容,所以就没有实现Copy,原因在于对他们的拷贝是一种非常消耗性能操作。

当然我们要为这种数据实现Copy也是可以的,但通常不会这样做。因为实现Copy后,虽然使用上是方便了,不用担心所有权问题,但每次都深拷贝了,就会在性能上变成了失控,我们当然不希望发生这样的事情。

如果我们写了一个struct,里面只有i32,希望在使用上作为基本的原子类型,也可以去实现Copy,只要加上#[drive(Copy)]即可。

总结

  • 基本类型默认实现了Copy(除了String,具体参考上文);
  • 需要分配内存或者某种形式的资源,想拷贝,就去实现Clone,而非Copy
  • 数据组合中全部是实现了Copy的类型,例如全部是i32的struct,可以根据使用情况选择Clone或Copy或者都不实现,一般是需要mut的实现Clone。