Copy trait
1 - Copy trait的std文档
https://doc.rust-lang.org/std/marker/trait.Copy.html
pub trait Copy: Clone { }
只需复制位即可复制其值的类型。
默认情况下,变量绑定具有 move语义。换句话说:
#[derive(Debug)]
struct Foo;
let x = Foo;
let y = x;
// `x` 已移至 `y`,因此无法使用
// println!("{:?}", x); // error: use of moved value
但是,如果类型实现 Copy,则它具有复制语义:
// 我们可以派生一个 `Copy` 实现。
// `Clone` 也是必需的,因为它是 `Copy` 的父特征。
#[derive(Debug, Copy, Clone)]
struct Foo;
let x = Foo;
let y = x;
// `y` 是 `x` 的副本
println!("{:?}", x); // A-OK!
重要的是要注意,在这两个示例中,唯一的区别是分配后是否允许您访问 x。 在后台,复制(copy)和移动(move)都可能导致将位复制到内存中,尽管有时会对其进行优化。
如何实现 Copy?
有两种方法可以在您的类型上实现 Copy。最简单的是使用 derive:
#[derive(Copy, Clone)]
struct MyStruct;
您还可以手动实现 Copy 和 Clone:
struct MyStruct;
impl Copy for MyStruct { }
impl Clone for MyStruct {
fn clone(&self) -> MyStruct {
*self
}
}
两者之间的区别很小: derive 策略还将 Copy 绑定在类型参数上,这并不总是需要的。
Copy 和 Clone 有什么区别?
复制是隐式发生的,例如作为分配 y = x 的一部分。Copy 的行为不可重载; 它始终是简单的按位复制。
克隆是一个明确的动作 x.clone()。Clone 的实现可以提供安全复制值所需的任何特定于类型的行为。 例如,用于 String的 Clone 的实现需要在堆中复制指向字符串的缓冲区。 String 值的简单按位副本将仅复制指针,从而导致该行向下双重释放。 因此,String是 Clone,但不是 Copy。
Clone 是 Copy 的父特征,因此 Copy 的所有类型也必须实现 Clone。 如果类型为 Copy,则其 Clone 实现仅需要返回 *self (请参见上面的示例)。
类型何时可以是 Copy?
如果类型的所有组件都实现 Copy,则它可以实现 Copy。例如,此结构体可以是 Copy:
#[derive(Copy, Clone)]
struct Point {
x: i32,
y: i32,
}
一个结构体可以是 Copy,而 i32 是 Copy,因此 Point 有资格成为 Copy。 相比之下,考虑
struct PointList {
points: Vec<Point>,
}
结构体 PointList 无法实现 Copy,因为 Vec 不是 Copy。如果尝试派生 Copy 实现,则会收到错误消息:
the trait `Copy` may not be implemented for this type; field `points` does not implement `Copy`
共享引用 (&T) 也是 Copy,因此,即使类型中包含不是 *Copy 类型的共享引用 T,也可以是 Copy。 考虑下面的结构体,它可以实现 Copy,因为它从上方仅对我们的非 Copy 类型 PointList 持有一个 shared 引用:
#[derive(Copy, Clone)]
struct PointListWrapper<'a> {
point_list_ref: &'a PointList,
}
什么时候类型不能为 Copy?
某些类型无法安全复制。例如,复制 &mut T 将创建一个别名可变引用。 复制 String 将重复管理 String 缓冲区,从而导致双重释放。
概括后一种情况,任何实现 Drop 的类型都不能是 Copy,因为它除了管理自己的 size_of:: 字节外还管理一些资源。
果您尝试在包含非 Copy 数据的结构或枚举上实现 Copy,则会收到 E0204 错误。
什么时候类型应该是 Copy?
一般来说,如果您的类型可以实现 Copy,则应该这样做。 但是请记住,实现 Copy 是您类型的公共 API 的一部分。 如果该类型将来可能变为非 Copy,则最好现在省略 Copy 实现,以避免 API 发生重大更改。
其他实现者
除下面列出的实现者外,以下类型还实现 Copy:
- 函数项类型 (即,为每个函数定义的不同类型)
- 函数指针类型 (例如
fn() -> i32) - 如果项类型也实现
Copy(例如[i32; 123456]),则所有大小的数组类型 - 如果每个组件还实现
Copy(例如(),(i32, bool)),则为元组类型 - 闭包类型,如果它们没有从环境中捕获任何值,或者所有此类捕获的值本身都实现了
Copy。 请注意,由共享引用捕获的变量始终实现Copy(即使引用对象没有实现),而由变量引用捕获的变量从不实现Copy。
2 - Copy trait的源码
https://github.com/rust-lang/rust/blob/master/library/core/src/marker.rs
#[stable(feature = "rust1", since = "1.0.0")]
#[lang = "copy"]
#[rustc_unsafe_specialization_marker]
pub trait Copy: Clone {
// Empty.
}
原始类型的Copy的实现。
无法在Rust中描述的实现是在 rustc_trait_selection 中的 traits::SelectionContext::copy_clone_conditions() 中实现。
mod copy_impls {
use super::Copy;
macro_rules! impl_copy {
($($t:ty)*) => {
$(
#[stable(feature = "rust1", since = "1.0.0")]
impl Copy for $t {}
)*
}
}
impl_copy! {
usize u8 u16 u32 u64 u128
isize i8 i16 i32 i64 i128
f32 f64
bool char
}
#[unstable(feature = "never_type", issue = "35121")]
impl Copy for ! {}
#[stable(feature = "rust1", since = "1.0.0")]
impl<T: ?Sized> Copy for *const T {}
#[stable(feature = "rust1", since = "1.0.0")]
impl<T: ?Sized> Copy for *mut T {}
/// Shared references can be copied, but mutable references *cannot*!
#[stable(feature = "rust1", since = "1.0.0")]
impl<T: ?Sized> Copy for &T {}
}
3 - [Rust编程之道笔记]Copy trait
copy trait 用来标识可以按位复制其值的类型,按位复制等价于c语言中的 memcpy。
pub trait Copy: Clone { }
copy trait 继承自 clone trait,意味着要实现 Copy trait 的类型,必须实现 Clone trait 中定义的方法。
要实现 Copy trait,就必须同时实现 Clone trait。
struct MyStruct;
impl Copy for MyStruct { }
impl Clone for MyStruct {
fn clone(&self) -> MyStruct {
*self
}
}
rust提供了更方便的 derive 属性:
#[derive(Copy, Clone)]
struct MyStruct;
copy 的行为是隐式行为,开发者不能重载 Copy 行为,它永远都是一个简单的位复制。
并非所有的类型都可以实现 Copy trait。