目录
- 0. 引言
- 1. Default Trait(不是dyn兼容的)
-
- 1.1 可派生
-
- 1.1.1 枚举
- 1.2 如何实现Default trait
- 1.3 必需方法
- 2. Clone Trait(不是dyn兼容的)
-
- 2.1 可派生
- 2.2 如何实现Clone
- 2.3 Clone与PartialEq/Eq
- 2.4 额外实现者
- 2.5 必需方法
- 2.6 提供方法
- 参考
0. 引言
default模块中只有Default Trait,clone模块中只有Clone Trait。
1. Default Trait(不是dyn兼容的)
pub trait Default: Sized {
// 必须实现的方法
fn default() -> Self;
}
一个用于为类型提供有效默认值的trait。在为类型实现Default前,必须实现Sized。 有时,你会想回退到某种默认值,而不特别关心它具体是什么。这种情况常见于定义一组选项的struct:
struct SomeOptions {
foo: i32,
bar: f32,
}
我们如何定义一些默认值呢?可以使用derive,要求结构体中每个字段的类型都实现了Default trait:
#[derive(Debug, Default)]
struct SomeOptions {
foo: i32,
bar: f32,
}
fn main() {
let options: SomeOptions = Default::default();
println!("{:?}", options);
}

1.1 可派生
如果类型的所有字段都实现了Default trait,就可以对该trait使用#[derive]。派生时,它会为每个字段使用其类型的默认值。
1.1.1 枚举
在enum上使用#[derive(Default)]时,需要选择哪个单元变体作为默认值。做法是将#[default]属性放在该变体上。
#[derive(Default)]
enum Kind {
#[default]
A,
B,
C,
}
不能非单元变体或非穷尽变体上使用#[default]属性。
1.2 如何实现Default trait
为default()方法提供一个实现,返回你的类型中应作为默认值的那个值。
enum Kind {
A,
B,
C,
}
impl Default for Kind {
fn default() -> Self {
Kind::A
}
}
1.3 必需方法
方法签名:
fn default() -> Self;
返回类型的默认值。默认值通常是某种初始值、单位元,或任何作为默认值有意义的东西。
2. Clone Trait(不是dyn兼容的)
pub trait Clone: Sized {
// 必需方法
fn clone(&self) -> Self;
// 提供方法
fn clone_from(&mut self, source: &Self) { … }
}
一个允许显式创建值副本的常用trait。 调用clone总会产生一个新值。但对于指向其他数据的类型,新值可能仍指向相同的底层数据,而非复制它。 这一区别在包含Arc<Mutex<T>>之类智能指针的结构体上使用#[derive(Clone)]时尤为重要——克隆出的结构体会与原结构体共享可变状态。 与Copy的区别在于:Copy是隐式的,开销低廉的按位复制,而Clone总是显式的,开销可能大也可能小。Copy没有方法,因此无法改变其行为;但实现Clone时,你提供的clone方法可能运行任意代码。
2.1 可派生
如果所有字段都是Clone的,就可以对该trait使用#[derive]。derive出的Clone实现会对每个字段调用clone。 对于泛型结构体,#[derive]会通过在泛型参数上添加Clone约束来有条件地实现Clone trait。
// 当T实现了Clone trait时,derive为Reading<T>实现Clone trait
#[derive(Clone)]
struct Reading<T> {
frequency: T,
}
2.2 如何实现Clone
属于Copy的类型应当有简单的Clone实现。若T: Copy、x: T且y: &T,则let x = y.clone();等价于lext x = *y;。手动实现时应小心维护这一不等式。但unsafe代码不得依赖它来保证内存安全。 一个例子是持有函数指针的泛型结构体。这种情况下Clone的实现无法通过derive获得,但可以这样实现:
struct Generate<T>(fn() -> T);
impl<T> Copy for Generate<T> {}
impl<T> Clone for Generate<T> {
fn clone(&self) -> Self {
*self
}
}
如果我们使用derive:
#[derive(Clone, Copy)]
struct Generate<T>(fn() -> T);
自动派生的实现会带有不必要的T: Copy和T: Clone约束:
// 自动派生
impl<T: Copy> Copy for Generate<T> {}
// 自动派生
impl<T: Clone> Clone for Generate<T> {
fn clone(&self) -> Generate<T> {
Generate(Clone::clone(&self.0))
}
}
这些约束是不必要的,因为函数指针本身是可复制、可克隆的,即使其返回类型不是:
#[derive(Clone, Copy)]
struct Generate<T>(fn() -> T);
struct NotCloneable;
fn generate_not_cloneable() -> NotCloneable {
NotCloneable
}
fn main() {
let _ = Generate(generate_not_cloneable).clone();
}

2.3 Clone与PartialEq/Eq
Clone用于对象的复制。因此,同时实现Clone和PartialEq时,以下性质应当成立: x == x -> x.clone() == x 换句话说,如果一个对象与自身比较相等,那么它的克隆也必须与原对象比较相等。 对于还实现了Eq trait的类型,x == x对其总是成立,这蕴含着x.clone() == x必须始终为真。标准库集集合如HashMap、HashSet、BTreeMap、BTreeSet和BinaryHeap的正确行为依赖其键遵守该性质。此外,这些集合要求克隆键后保持Hash和Ord方法的结果不变。所幸,只要Hash和Ordan各自的要求正确实现,这一点会自动从x.clone() == x中得出。 使用#[derive(Clone, PartialEq)]同时派生Clone和PartialEq,或用#[derive(Clone, PartialEq, Eq)]额外派生Eq时,该性质会自动得到维护——前提是底层类型满足它。 违反该性质属于逻辑错误。逻辑错误导致的行为未作规定,但该trait的实现者必须确保此类逻辑错误不会导致未定义行为。这意味着unsafe代码不得依赖该性质成立。
2.4 额外实现者
标准库中很多类型实现了Clone trait,不在这里列出,等讲到该类型的时候在实现的trait中讲述。 以下类型也实现了Clone trait: 函数项类型(为每个函数定义的独立类型) 函数指针类型(fn() -> i32) 闭包类型——前提是不从环境中捕获任何值,或所有被捕获的值自身都实现了Clone trait。以共享引用捕获的变量总是实现Clone(即使被指者不实现),而以可变引用捕获的变量从不实现Clone。
2.5 必需方法
方法签名:
fn clone(&self) -> Self;
返回该值的一个副本。副本的含义因类型而异: 对于大多数类型,这会创建一个深度独立的副本。 对&T这样的引用类型,会创建指向同一个值的另一个引用。 对Arc或Rc这样的智能指针,这会增加引用计数,但仍指向相同的底层数据。
fn main() {
let hello = "hello"; // &str实现了Clone
println!("{}", hello.clone());
}

use std::sync::{Arc, Mutex};
fn main() {
let data = Arc::new(Mutex::new(vec![1, 2, 3]));
let data_clone = data.clone(); // 对同一个Mutex创建另一个Arc指针
{
let mut lock = data.lock().unwrap();
lock.push(4);
}
// data_clone也改变了,因为它们共享同一份底层数据
println!("{:?}", data_clone.lock().unwrap());
}

2.6 提供方法
方法签名:
fn clone_from(&mut self, source: &Self)
从source执行复制赋值。 a.clone_from(&b)在功能上等价于a = b.clone(),但可以被重写以复用a的资源,避免不必要的分配。
参考
1、Rust std::default 2、Rust std::clone



