本文简要介绍rust语言中 Trait std::marker::Copy
的用法。
用法
pub trait Copy: Clone { }
可以简单地通过复制位来复制其值的类型。
默认情况下,变量绑定有 'move semantics.' 换句话说:
#[derive(Debug)]
struct Foo;
let x = Foo;
let y = x;
// `x` has moved into `y`, and so cannot be used
// println!("{:?}", x); // error: use of moved value
但是,如果一个类型实现了 Copy
,则它改为具有 'copy semantics':
// We can derive a `Copy` implementation. `Clone` is also required, as it's
// a supertrait of `Copy`.
#[derive(Debug, Copy, Clone)]
struct Foo;
let x = Foo;
let y = x;
// `y` is a copy of `x`
println!("{:?}", x); // A-OK!
需要注意的是,在这两个示例中,唯一的区别是是否允许您在分配后访问x
。在幕后,复制和移动都可能导致位被复制到内存中,尽管有时这会被优化掉。
如何实现 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
的实现可以提供安全复制值所需的任何 type-specific 行为。例如 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<T>
不是 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
从上面:
#[derive(Copy, Clone)]
struct PointListWrapper<'a> {
point_list_ref: &'a PointList,
}
什么时候不能我的类型是Copy
?
某些类型无法安全复制。例如,复制 &mut T
将创建一个别名可变引用。复制 String
将重复管理 String
缓冲区的责任,从而导致双重释放。
概括后一种情况,任何实现 Drop
的类型都不能是 Copy
,因为它除了自己的 size_of::<T>
字节之外还管理一些资源。
如果您尝试在包含非 Copy
数据的结构或枚举上实现 Copy
,您将收到错误 E0204 。
什么时候应该我的类型是Copy
?
一般来说,如果您的类型能够实施Copy
, 它应该。但请记住,实施Copy
是您的类型的公共 API 的一部分。如果该类型可能变为非Copy
将来,谨慎的做法可能是省略Copy
现在实施,以避免重大 API 更改。
其他实现者
除了下面列出的实现者之外,以下类型还实现 Copy
:
- 函数项类型(即为每个函数定义的不同类型)
- 函数指针类型(例如,
fn() -> i32
) - 元组类型,如果每个组件也实现
Copy
(例如,()
,(i32, bool)
) - 闭包类型,如果它们没有从环境中捕获任何值,或者所有这些捕获的值都实现了
Copy
。请注意,共享引用捕获的变量始终实现Copy
(即使引用对象没有),而可变引用捕获的变量从不实现Copy
。
外来类型的实现
相关用法
- Rust Copy用法及代码示例
- Rust Condvar.notify_all用法及代码示例
- Rust Command.args用法及代码示例
- Rust Condvar.wait用法及代码示例
- Rust Cow.is_owned用法及代码示例
- Rust Cow用法及代码示例
- Rust Condvar.wait_timeout用法及代码示例
- Rust Condvar.wait_timeout_while用法及代码示例
- Rust Command.env用法及代码示例
- Rust Command.env_remove用法及代码示例
- Rust Command.get_args用法及代码示例
- Rust Command.stdout用法及代码示例
- Rust Command.stdin用法及代码示例
- Rust Components用法及代码示例
- Rust Component.as_os_str用法及代码示例
- Rust ControlFlow用法及代码示例
- Rust Command.current_dir用法及代码示例
- Rust Command.output用法及代码示例
- Rust ControlFlow.break_value用法及代码示例
- Rust Command.status用法及代码示例
- Rust Cow.into_owned用法及代码示例
- Rust Condvar.wait_while用法及代码示例
- Rust Command.envs用法及代码示例
- Rust Command用法及代码示例
- Rust Command.get_program用法及代码示例
注:本文由纯净天空筛选整理自rust-lang.org大神的英文原创作品 Trait std::marker::Copy。非经特殊声明,原始代码版权归原作者所有,本译文未经允许或授权,请勿转载或复制。