文章目录[x]
- 1:Copy
- 1.1:概述
- 1.2:特点
- 1.3:实现条件
- 1.4:示例
- 1.5:适用类型
- 2:Clone
- 2.1:概述
- 2.2:特点
- 2.3:定义
- 2.4:示例
- 2.5:Copy vs Clone 对比
- 3:Send
- 3.1:概述
- 3.2:特点
- 3.3:定义
- 3.4:示例
- 3.5:常见的非 Send 类型
- 3.6:常见的 Send 类型
- 4:Sync
- 4.1:概述
- 4.2:特点
- 4.3:定义
- 4.4:示例
- 4.5:Send 和 Sync 的关系
- 4.6:常见的非 Sync 类型
- 5:Drop
- 5.1:概述
- 5.2:特点
- 5.3:定义
- 5.4:示例
- 5.5:注意事项
- 6:Default
- 6.1:概述
- 6.2:定义
- 6.3:示例
- 7:Debug
- 7.1:概述
- 7.2:定义
- 7.3:示例
- 8:Display
- 8.1:概述
- 8.2:定义
- 8.3:示例
- 9:PartialEq 和 Eq
- 9.1:PartialEq
- 9.2:Eq
- 9.3:示例
- 10:PartialOrd 和 Ord
- 10.1:PartialOrd
- 10.2:Ord
- 10.3:示例
- 11:From 和 Into
- 11.1:From
- 11.2:Into
- 11.3:示例
- 12:AsRef 和 AsMut
- 12.1:AsRef
- 12.2:AsMut
- 12.3:示例
- 13:Deref 和 DerefMut
- 13.1:Deref
- 13.2:DerefMut
- 13.3:示例
- 13.4:Deref 强制转换规则
- 14:Iterator
- 14.1:概述
- 14.2:定义
- 14.3:示例
- 14.4:三种迭代器方法
- 15:总结对比表
- 16:实践建议
- 17:参考资源
本文将介绍Rust开发中常见的trait。
Copy
概述
Copy 是一个标记 trait(marker trait),表示类型的值可以通过简单的位拷贝(bitwise copy)来复制。
特点
- 自动复制:赋值或传参时自动复制值,而不是移动所有权
- 栈上分配:只能用于完全存储在栈上的类型
- 隐式行为:复制是隐式发生的,无需显式调用
- 必须实现 Clone:
Copy是Clone的子 trait
实现条件
- 类型的所有字段都必须实现
Copy - 不能有自定义的
Drop实现 - 通常是简单的标量类型或由这些类型组成的结构体
示例
// 基本类型都实现了 Copy
let x = 5;
let y = x; // x 被复制,而非移动
println!("x = {}, y = {}", x, y); // x 仍然有效
// 自定义类型实现 Copy
#[derive(Copy, Clone)]
struct Point {
x: i32,
y: i32,
}
let p1 = Point { x: 1, y: 2 };
let p2 = p1; // p1 被复制
println!("p1: ({}, {})", p1.x, p1.y); // p1 仍然有效
// 不能实现 Copy 的例子(包含堆分配)
struct NotCopy {
data: String, // String 不是 Copy,所以整个结构体不能是 Copy
}
适用类型
- 所有整数类型(i8, u32, etc.)
- 浮点类型(f32, f64)
- 布尔类型(bool)
- 字符类型(char)
- 元组(如果所有元素都是 Copy)
- 数组(如果元素类型是 Copy)
Clone
概述
Clone trait 提供显式的深拷贝功能,允许复制堆上的数据。
特点
- 显式调用:需要明确调用
.clone()方法 - 深拷贝:可以复制堆上的数据
- 可能昂贵:克隆操作可能涉及大量内存分配
定义
pub trait Clone {
fn clone(&self) -> Self;
fn clone_from(&mut self, source: &Self) {
*self = source.clone()
}
}
示例
// String 实现了 Clone
let s1 = String::from("hello");
let s2 = s1.clone(); // 显式克隆
println!("s1 = {}, s2 = {}", s1, s2);
// 自定义类型
#[derive(Clone)]
struct Person {
name: String,
age: u32,
}
let person1 = Person {
name: String::from("Alice"),
age: 30,
};
let person2 = person1.clone();
// 手动实现 Clone
struct CustomData {
data: Vec<i32>,
}
impl Clone for CustomData {
fn clone(&self) -> Self {
println!("克隆操作被执行");
CustomData {
data: self.data.clone(),
}
}
}
Copy vs Clone 对比
| 特性 | Copy | Clone |
|---|---|---|
| 调用方式 | 隐式 | 显式 .clone() |
| 适用范围 | 仅栈上数据 | 栈和堆数据 |
| 性能 | 快速(位拷贝) | 可能较慢 |
| 实现要求 | 必须实现 Clone | 独立 trait |
Send
概述
Send 是一个标记 trait,表示类型的所有权可以安全地在线程间转移。
特点
- 自动实现:大多数类型自动实现
- 编译器保证:在编译时确保线程安全
- 所有权转移:允许将值的所有权从一个线程发送到另一个线程
定义
pub unsafe auto trait Send { }
示例
use std::thread;
// 实现了 Send 的类型
let data = vec![1, 2, 3, 4];
let handle = thread::spawn(move || {
println!("数据: {:?}", data); // data 的所有权转移到新线程
});
handle.join().unwrap();
// 不实现 Send 的例子:Rc
use std::rc::Rc;
let rc = Rc::new(5);
// 下面的代码会编译错误,因为 Rc 不是 Send
// let handle = thread::spawn(move || {
// println!("{}", rc);
// });
常见的非 Send 类型
Rc<T>:引用计数指针(非线程安全)*const T和*mut T:裸指针std::rc::Weak<T>
常见的 Send 类型
- 基本类型(i32, f64, bool, etc.)
String,Vec<T>(如果 T 是 Send)Arc<T>(如果 T 是 Send + Sync)Mutex<T>,RwLock<T>
Sync
概述
Sync 是一个标记 trait,表示类型可以安全地在多个线程间共享引用。
特点
- 引用共享:
&T可以在线程间传递 - 关系:
T是Sync当且仅当&T是Send - 自动实现:由编译器自动推导
定义
pub unsafe auto trait Sync { }
示例
use std::sync::{Arc, Mutex};
use std::thread;
// Arc<Mutex<T>> 允许多线程共享
let counter = Arc::new(Mutex::new(0));
let mut handles = vec![];
for _ in 0..10 {
let counter_clone = Arc::clone(&counter);
let handle = thread::spawn(move || {
let mut num = counter_clone.lock().unwrap();
*num += 1;
});
handles.push(handle);
}
for handle in handles {
handle.join().unwrap();
}
println!("结果: {}", *counter.lock().unwrap());
Send 和 Sync 的关系
// 如果 T 实现了 Sync,那么 &T 实现了 Send
// 如果 T 实现了 Send,那么 T 可以被移动到其他线程
// 组合规则:
// - T: Send + Sync => 可以在线程间安全移动和共享
// - T: Send + !Sync => 可以移动,但不能共享(如 Cell)
// - T: !Send + Sync => 不常见
// - T: !Send + !Sync => 只能在单线程使用(如 Rc)
常见的非 Sync 类型
Cell<T>和RefCell<T>:内部可变性,非线程安全Rc<T>:引用计数,非线程安全*const T和*mut T:裸指针
Drop
概述
Drop trait 允许在值离开作用域时执行清理代码。
特点
- 自动调用:变量离开作用域时自动调用
- 资源清理:用于释放资源(文件、网络连接、锁等)
- 不能手动调用:不能直接调用
drop()方法,使用std::mem::drop()代替
定义
pub trait Drop {
fn drop(&mut self);
}
示例
struct FileHandler {
filename: String,
}
impl Drop for FileHandler {
fn drop(&mut self) {
println!("关闭文件: {}", self.filename);
}
}
fn main() {
let _file = FileHandler {
filename: String::from("data.txt"),
};
println!("文件处理器创建完成");
// _file 在这里离开作用域,自动调用 drop
}
// 提前释放
let x = String::from("hello");
std::mem::drop(x); // 显式释放
// println!("{}", x); // 编译错误:x 已被释放
注意事项
- 实现了
Drop的类型不能实现Copy - Drop 的执行顺序:变量按声明的相反顺序被 drop
- 析构顺序:先 drop 父结构体,再 drop 字段
Default
概述
Default trait 提供类型的默认值。
定义
pub trait Default {
fn default() -> Self;
}
示例
// 使用默认值
let v: Vec<i32> = Default::default();
let s: String = Default::default();
// 自定义默认值
#[derive(Default)]
struct Config {
debug: bool, // false
max_connections: u32, // 0
}
// 手动实现
struct CustomConfig {
timeout: u64,
retries: u32,
}
impl Default for CustomConfig {
fn default() -> Self {
CustomConfig {
timeout: 30,
retries: 3,
}
}
}
// 结构体更新语法
let config = Config {
debug: true,
..Default::default()
};
Debug
概述
Debug trait 用于格式化输出,主要用于调试。
定义
pub trait Debug {
fn fmt(&self, f: &mut Formatter<'_>) -> Result;
}
示例
#[derive(Debug)]
struct User {
username: String,
age: u32,
}
let user = User {
username: String::from("alice"),
age: 30,
};
println!("{:?}", user); // User { username: "alice", age: 30 }
println!("{:#?}", user); // 美化输出
// 手动实现
struct Point {
x: i32,
y: i32,
}
impl std::fmt::Debug for Point {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "Point({}, {})", self.x, self.y)
}
}
Display
概述
Display trait 用于面向用户的格式化输出。
定义
pub trait Display {
fn fmt(&self, f: &mut Formatter<'_>) -> Result;
}
示例
struct Point {
x: i32,
y: i32,
}
impl std::fmt::Display for Point {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "({}, {})", self.x, self.y)
}
}
let p = Point { x: 3, y: 4 };
println!("{}", p); // (3, 4)
// Display vs Debug
// {:?} 或 {:#?} => Debug
// {} => Display
PartialEq 和 Eq
PartialEq
用于部分等价关系,支持 == 和 != 运算符。
pub trait PartialEq<Rhs = Self> {
fn eq(&self, other: &Rhs) -> bool;
fn ne(&self, other: &Rhs) -> bool { !self.eq(other) }
}
Eq
用于完全等价关系,是 PartialEq 的子 trait。
pub trait Eq: PartialEq<Self> { }
示例
#[derive(PartialEq, Eq)]
struct Point {
x: i32,
y: i32,
}
let p1 = Point { x: 1, y: 2 };
let p2 = Point { x: 1, y: 2 };
assert_eq!(p1, p2);
// 浮点数只实现 PartialEq,不实现 Eq
// 因为 NaN != NaN
let x = f64::NAN;
assert!(x != x);
// 自定义实现
struct CaseInsensitiveString(String);
impl PartialEq for CaseInsensitiveString {
fn eq(&self, other: &Self) -> bool {
self.0.to_lowercase() == other.0.to_lowercase()
}
}
PartialOrd 和 Ord
PartialOrd
用于部分排序,支持 <, <=, >, >= 运算符。
pub trait PartialOrd<Rhs = Self>: PartialEq<Rhs> {
fn partial_cmp(&self, other: &Rhs) -> Option<Ordering>;
}
Ord
用于全序关系。
pub trait Ord: Eq + PartialOrd<Self> {
fn cmp(&self, other: &Self) -> Ordering;
}
示例
use std::cmp::Ordering;
#[derive(Eq, PartialEq, PartialOrd, Ord)]
struct Version {
major: u32,
minor: u32,
patch: u32,
}
let v1 = Version { major: 1, minor: 2, patch: 3 };
let v2 = Version { major: 1, minor: 3, patch: 0 };
assert!(v1 < v2);
// 手动实现
struct Person {
name: String,
age: u32,
}
impl PartialOrd for Person {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
self.age.partial_cmp(&other.age)
}
}
impl Ord for Person {
fn cmp(&self, other: &Self) -> Ordering {
self.age.cmp(&other.age)
}
}
From 和 Into
From
用于值到值的转换。
pub trait From<T> {
fn from(value: T) -> Self;
}
Into
From 的倒置,自动实现。
pub trait Into<T> {
fn into(self) -> T;
}
示例
// From 示例
let s = String::from("hello");
let num = i32::from(5u8);
// 自定义 From
struct Kilometers(i32);
impl From<Miles> for Kilometers {
fn from(miles: Miles) -> Self {
Kilometers((miles.0 as f64 * 1.60934) as i32)
}
}
struct Miles(i32);
let miles = Miles(10);
let km: Kilometers = Kilometers::from(miles);
// 或使用 Into
let miles = Miles(10);
let km: Kilometers = miles.into();
// 在函数参数中使用
fn print_string(s: impl Into<String>) {
let string = s.into();
println!("{}", string);
}
print_string("hello"); // &str -> String
print_string(String::from("world")); // String -> String
AsRef 和 AsMut
AsRef
用于廉价的引用到引用转换。
pub trait AsRef<T: ?Sized> {
fn as_ref(&self) -> &T;
}
AsMut
可变引用版本。
pub trait AsMut<T: ?Sized> {
fn as_mut(&mut self) -> &mut T;
}
示例
// AsRef 用于泛型参数
fn print_str(s: impl AsRef<str>) {
println!("{}", s.as_ref());
}
print_str("hello");
print_str(String::from("world"));
// String 和 Vec 的 AsRef 实现
let s = String::from("hello");
let slice: &str = s.as_ref();
let v = vec![1, 2, 3];
let slice: &[i32] = v.as_ref();
// Path 示例
use std::path::Path;
fn process_path(p: impl AsRef<Path>) {
let path = p.as_ref();
println!("{:?}", path);
}
process_path("file.txt");
process_path(Path::new("/usr/bin"));
Deref 和 DerefMut
Deref
允许通过 * 运算符解引用。
pub trait Deref {
type Target: ?Sized;
fn deref(&self) -> &Self::Target;
}
DerefMut
可变版本。
pub trait DerefMut: Deref {
fn deref_mut(&mut self) -> &mut Self::Target;
}
示例
use std::ops::Deref;
struct MyBox<T>(T);
impl<T> MyBox<T> {
fn new(x: T) -> MyBox<T> {
MyBox(x)
}
}
impl<T> Deref for MyBox<T> {
type Target = T;
fn deref(&self) -> &T {
&self.0
}
}
let x = MyBox::new(5);
assert_eq!(5, *x); // 解引用
// Deref 强制转换
fn hello(name: &str) {
println!("Hello, {}!", name);
}
let m = MyBox::new(String::from("Rust"));
hello(&m); // MyBox<String> -> &String -> &str
// String 实现了 Deref<Target=str>
let s = String::from("hello");
let slice: &str = &s; // 自动 deref
Deref 强制转换规则
T: Deref<Target=U>=>&T转换为&UT: DerefMut<Target=U>=>&mut T转换为&mut UT: Deref<Target=U>=>&mut T转换为&U
Iterator
概述
Iterator trait 用于遍历序列。
定义
pub trait Iterator {
type Item;
fn next(&mut self) -> Option<Self::Item>;
// 许多默认方法
// map, filter, fold, collect, etc.
}
示例
// 使用迭代器
let v = vec![1, 2, 3];
let mut iter = v.iter();
assert_eq!(iter.next(), Some(&1));
assert_eq!(iter.next(), Some(&2));
// 迭代器方法链
let v: Vec<i32> = (1..10)
.filter(|x| x % 2 == 0)
.map(|x| x * x)
.collect();
// v = [4, 16, 36, 64]
// 自定义迭代器
struct Counter {
count: u32,
}
impl Counter {
fn new() -> Counter {
Counter { count: 0 }
}
}
impl Iterator for Counter {
type Item = u32;
fn next(&mut self) -> Option<Self::Item> {
if self.count < 5 {
self.count += 1;
Some(self.count)
} else {
None
}
}
}
let sum: u32 = Counter::new().sum();
assert_eq!(sum, 15);
// for 循环使用 IntoIterator
let v = vec![1, 2, 3];
for item in v { // v.into_iter()
println!("{}", item);
}
三种迭代器方法
iter()=>&T(不可变引用)iter_mut()=>&mut T(可变引用)into_iter()=>T(获取所有权)
总结对比表
| Trait | 用途 | 实现方式 | 关键点 |
|---|---|---|---|
| Copy | 隐式复制 | 派生 | 仅栈数据,快速 |
| Clone | 显式复制 | 派生或手动 | 可复制堆数据 |
| Send | 线程间转移所有权 | 自动 | 线程安全标记 |
| Sync | 线程间共享引用 | 自动 | 多线程共享 |
| Drop | 资源清理 | 手动 | 自动调用 |
| Default | 提供默认值 | 派生或手动 | 构造便利 |
| Debug | 调试输出 | 派生或手动 | {:?} 格式 |
| Display | 用户输出 | 手动 | {} 格式 |
| PartialEq/Eq | 相等比较 | 派生或手动 | == 运算符 |
| PartialOrd/Ord | 排序比较 | 派生或手动 | < 运算符 |
| From/Into | 类型转换 | 手动 | 值转换 |
| AsRef/AsMut | 引用转换 | 手动 | 廉价转换 |
| Deref/DerefMut | 解引用 | 手动 | 智能指针 |
| Iterator | 序列遍历 | 手动 | next() 方法 |
实践建议
- 优先使用派生:能用
#[derive]就不手动实现 - 理解所有权:
CopyvsClone的选择影响性能 - 线程安全:使用
Send + Sync确保并发安全 - 智能转换:利用
From/Into和AsRef让 API 更友好 - 迭代器优先:使用迭代器而非索引循环
- 实现一致性:实现
PartialEq时考虑是否需要Eq