Rust的Copy与Clone

先说结论, Copy是给编译器看的, Clone是给程序员用的. Clone显示指定资源的流向.

为什么区分Copy与Clone?
因为所有权, move语义, 用来对内存资源流动方向的管理.

Copy是简单的内存拷贝.一般是在栈上比如:int, bool...在执行完函数后就没了.
但堆上数据呢? Vec何时释放? 函数执行完? 完蛋
每个变量名对应一个内存资源. 在不消耗原有内存资源的情况下实现内存资源的转移.
必须显示指定资源的流向. 因此需要显示使用Clone.

总结
这里引用知乎F001的总结

Copy内部没有方法,Clone内部有两个方法。
用法
Copy trait 是给编译器用的,告诉编译器这个类型默认采用 copy 语义,而不是 move 语义。
Clone trait 是给程序员用的,我们必须手动调用clone方法,它才能发挥作用。
实现
Copy trait不是你想实现就实现,它对类型是有要求的,有些类型就不可能 impl Copy例如: String。
Clone trait 没有什么前提条件,任何类型都可以实现unsized 类型除外。
Copy trait规定了这个类型在执行变量绑定、函数参数传递、函数返回等场景下的操作方式。即这个类型在这种场景下,必然执行的是简单内存拷贝操作,这是由编译器保证的,程序员无法控制。
Clone trait 里面的 clone 方法究竟会执行什么操作,则是取决于程序员自己写的逻辑。一般情况下,clone 方法应该执行一个“深拷贝”操作,但这不是强制的,如果你愿意,也可以在里面启动一个人工智能程序,都是有可能的。
如果你确实需要Clone trait执行“深拷贝”操作,编译器帮我们提供了一个工具,我们可以在一个类型上添加#[derive(Clone)],来让编译器帮我们自动生成那些重复的代码。
实现了Copy后, Clone含义也要符合Copy语义.Rust语言规定了当T: Copy的情况下,Clone trait代表的含义。即:当某变量let t: T;,符合T: Copy时, 它调用 let x = t.clone() 方法的时候,它的含义必须等同于“简单内存拷贝”。也就是说,clone的行为必须等同于let x = std::ptr::read(&t);,也等同于let x = t;。当T: Copy时,我们不要在Clone trait里面乱写自己的逻辑。所以,当我们需要指定一个类型是 Copy 的时候,最好顺便也指定它 Clone 的行为,就是编译器为我们自动生成的那个逻辑。正因为如此,在希望让一个类型具有 Copy 性质的时候,一般使用 #[derive(Copy, Clone)] 这种方式,这种情况下它们俩最好一起出现,避免手工实现 Clone 导致错误

Copy 和 Clone
Copy

可以用在类似整型这样在栈中存储的类型,实现类似深拷贝的效果。如果一个类型拥有 Copy 特征,一个旧的变量在被赋值给其他变量后仍然可用。
任何基本类型的组合都实现了 Copy。例如:
所有整数类型,比如 u32。
布尔类型,bool,它的值是 true 和 false。
所有浮点数类型,比如 f64。
字符类型,char。
元组,当且仅当其包含的类型也都是 Copy 的时候。比如,(i32, i32) 是 Copy 的,但 (i32, String) 就不是。
不可变引用 &T,但是注意: 可变引用 &mut T 是不可以 Copy 的。
Copy 是给编译器用的,对用户透明。
Clone

对于存储在堆中的数据,当一个值被移动时,Rust 会做一个浅拷贝;如果想创建一个像 C++ 那样的深拷贝呢,需要实现 Clone Trait。
Clone trait 是给用户用的,用户需要手动调用 clone 方法。

posted @ 2022-10-10 15:14  方东信  阅读(594)  评论(0编辑  收藏  举报