1. ownership - 所有权(本质就是默认移动)
默认移动语义
Rust 默认使用移动语义,拷贝必须显式调用 .clone()。
1 2 3 4 5 6
| let v1 = vec![1, 2, 3]; let v2 = v1;
let v3 = v2.clone(); println!("{:?}, {:?}", v2, v3);
|
**对比 C++**:C++ 默认拷贝,移动需显式 std::move(),且移动后对象仍可使用(状态未定义)。Rust 编译期禁止使用已移动的值。
Copy trait 例外:基本类型(i32、bool、f64 等)实现了 Copy,自动拷贝:
Copy vs 非 Copy 的决定因素
是否实现 Copy trait 决定行为:
| 类型 |
Copy? |
赋值行为 |
原因 |
| i32, f64, bool, char |
✅ |
拷贝 |
栈分配,拷贝成本为零 |
| String, Vec, Box |
❌ |
移动 |
堆分配,有所有权 |
| 自定义 struct |
默认 ❌ |
移动 |
需显式 derive Copy |
实现 Copy 的条件:
- 所有字段都实现 Copy
- 没有 Drop(不能有自定义析构)
1 2 3 4 5 6 7 8 9 10
| struct Point { x: i32, y: i32 } let p1 = Point { x: 1, y: 2 }; let p2 = p1;
#[derive(Copy, Clone)] struct PointCopy { x: i32, y: i32 } let p3 = PointCopy { x: 1, y: 2 }; let p4 = p3;
|
#[derive(…)] 编译期代码生成
derive 不是注解反射,是编译器自动生成 trait 实现:
1 2 3
| #[derive(Copy, Clone)] struct Point { x: i32, y: i32 }
|
对比其他语言:
- Java 注解:运行时反射,有开销
- C++ 宏:预处理器文本替换
- Rust derive:编译期代码生成,零运行时成本
常见 derive:Clone、Copy、Debug、Default、PartialEq、Eq、Hash
2. borrow - 借用规则
mut 可变声明
Rust 默认不可变,mut 显式声明可变:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| let x = 5;
let mut y = 5; y = 10;
let mut s = String::from("hello"); s.push_str(" world");
let r1 = &s; let r2 = &s;
let r3 = &mut s; r3.push_str("!");
|
**对比 C++**:
- Rust
let x = 5; ≈ C++ const int x = 5;
- Rust
let mut x = 5; ≈ C++ int x = 5;
- Rust 默认不可变,C++ 默认可变
切片引用
切片是对序列的部分引用,语法 [start..end],左闭右开 [start, end):
1 2 3 4 5 6 7 8 9
| let s = String::from("hello world"); let hello = &s[0..5]; let world = &s[6..11]; let full = &s[..]; let start = &s[..5]; let end = &s[6..];
let arr = [1, 2, 3, 4, 5]; let slice = &arr[1..3];
|
切片类型:&str(字符串切片)、&[T](数组切片)
3. enum_demo - Option/Result
格式化输出
| 标志 |
用途 |
说明 |
{} |
Display |
用户友好输出 |
{:?} |
Debug |
调试输出,需 #[derive(Debug)] |
{:#?} |
Debug |
美化缩进输出 |
1 2 3 4 5 6
| #[derive(Debug)] struct User { name: String, age: u32 }
let u = User { name: "Tom".into(), age: 25 }; println!("{:?}", u); println!("{:#?}", u);
|
match 模式匹配
类似 C++ switch 但更强大,可解构数据:
1 2 3 4 5 6
| match msg { Message::Quit => handle_quit(), Message::Move { x, y } => move_player(x, y), Message::Write(text) => save_text(text), _ => println!("其他"), }
|
对比 C++ switch:
| 特性 |
Rust match |
C++ switch |
| 匹配类型 |
任意类型、枚举、结构体 |
仅整数/字符 |
| 提取值 |
✅ 可解构内部数据 |
❌ 不能 |
| 必须完整 |
✅ 必须覆盖所有分支 |
❌ 可能漏 |
注意:数组模式匹配只能用于固定大小数组 [T; N],不能用于 Vec<T>:
1 2 3 4 5 6
| let arr: [i32; 5] = [1, 2, 3, 4, 5]; match arr { [1, second, ..] => println!("首是1,第二个是 {}", second), [first, ..] if first > 10 => println!("首大于10"), _ => println!("其他"), }
|
匹配守卫:在模式后加 if 条件进一步筛选:
1 2 3 4 5 6 7 8 9
| match msg { Message::ChangeColor(r, g, b) if r == 0 && g == 0 && b == 0 => { println!("黑色"); } Message::ChangeColor(r, g, b) => { println!("RGB({}, {}, {})", r, g, b); } _ => {} }
|
Option 和 Some
Rust 没有 null,用 Option<T> 表示可能不存在的值:
1 2 3 4 5 6 7
| enum Option<T> { Some(T), None, }
let some_value: Option<i32> = Some(42); let no_value: Option<i32> = None;
|
if let 和 while let
if let:只匹配一种模式,简化 match:
1 2 3 4 5 6 7 8 9 10 11 12
| let some_value = Some(3);
match some_value { Some(n) => println!("值是 {}", n), _ => (), }
if let Some(n) = some_value { println!("值是 {}", n); }
|
while let:循环匹配直到不符合:
1 2 3 4
| let mut stack = vec![1, 2, 3]; while let Some(top) = stack.pop() { println!("弹出: {}", top); }
|
pop() 方法:移除并返回顶部元素,返回 Option<T>,空时返回 None。
4. error - 错误处理
Rust 没有异常,用 Result<T, E> 和 Option<T> 处理错误:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| enum Result<T, E> { Ok(T), Err(E), }
fn divide(a: f64, b: f64) -> Result<f64, String> { if b == 0.0 { Err("除零错误".to_string()) } else { Ok(a / b) } }
match divide(10.0, 2.0) { Ok(v) => println!("结果: {}", v), Err(e) => println!("错误: {}", e), }
fn read_file(path: &str) -> Result<String, io::Error> { let mut file = File::open(path)?; let mut content = String::new(); file.read_to_string(&mut content)?; Ok(content) }
|
**对比 C++**:Rust 强制处理错误,编译期保证;C++ 异常可能被忽略。
5. struct_demo - 结构体
结构体更新语法
..对象名 从已有实例复制剩余字段,必须放最后:
1 2 3 4
| let user2 = User { email: String::from("new@example.com"), ..user1 };
|
注意所有权:非 Copy 字段会被移动,原对象可能失效。
impl 实现关键字
用于给类型添加方法或实现 trait:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| impl User { fn new(name: String) -> User { User { name, age: 0 } }
fn describe(&self) -> String { format!("{}: {}", self.name, self.age) }
fn grow(&mut self) { self.age += 1; } }
|
self 的三种形式:
| 形式 |
权限 |
说明 |
| 无 self |
不能访问实例 |
关联函数,类似静态方法 |
&self |
只读访问 |
只能读取成员 |
&mut self |
可读写访问 |
可修改成员 |
(待补充)
6. trait_demo - Trait
Trait 定义与实现
Trait 定义接口规范,类似 C++ 纯虚基类:
1 2 3 4 5 6 7 8 9 10 11
| trait Summary { fn summarize(&self) -> String; }
struct Article { title: String }
impl Summary for Article { fn summarize(&self) -> String { format!("文章: {}", self.title) } }
|
**对比 C++**:
| Rust Trait |
C++ 概念 |
trait Summary |
纯虚基类(只有纯虚函数) |
impl Trait for Type |
继承并实现接口 |
| Trait 无数据成员 |
基类可有数据成员 |
泛型与 Trait Bound
1 2 3 4 5 6 7 8 9 10 11
| fn print<T: Summary>(item: &T) { println!("{}", item.summarize()); }
fn process<T, U>(t: &T, u: &U) where T: Summary, U: Summary + std::fmt::Display, { ... }
|
Trait bound:约束泛型必须实现某些 trait,编译期强制检查。
impl Trait 返回值
1 2 3
| fn create() -> impl Summary { Article { ... } }
|
类似 C++ 返回基类指针,但编译期单态化,零开销。只能返回一种具体类型。
dyn Trait 动态分发
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| let items: Vec<Box<dyn Summary>> = vec ![ Box::new(Article { ... }), Box::new(Tweet { ... }), ];
fn factory(kind: &str) -> Box<dyn Summary> { match kind { "article" => Box::new(Article { ... }), "tweet" => Box::new(Tweet { ... }), _ => panic!(), } }
let item = factory("article"); println!("{}", item.summarize());
let items: Vec<Box<dyn Summary>> = vec![ factory("article"), factory("tweet"), ]; for item in items { println!("{}", item.summarize()); }
|
对比:
impl Trait |
dyn Trait |
| 编译期单态化 |
运行时多态 |
| 零开销 |
虚函数开销 |
| 固定一种类型 |
可存储多类型 |
Box 堆分配
Box<T> ≈ C++ std::unique_ptr<T>,堆分配智能指针:
1 2 3 4 5
| let b = Box::new(42); println!("{}", *b);
let item: Box<dyn Summary> = Box::new(Article { ... });
|
栈 vs 堆分配规则:
| 类型 |
内存位置 |
说明 |
| i32, f64, bool, char |
栈 |
大小固定,编译期已知 |
[T; N] 固定数组 |
栈 |
大小固定 |
| struct 字段 |
栈 |
字段在栈则在栈 |
| String, Vec<T> |
栈+堆 |
栈存指针/长度,堆存数据 |
| Box<T> |
栈存指针,堆存数据 |
显式堆分配 |
1 2 3
| let s = String::from("hello");
|
判断方法:编译期能确定大小 → 栈,否则需要堆(或引用/Box)。
注意:::new() 只是命名习惯,不代表一定在堆上(如 String::new() 是空字符串)。
常见标准 Trait
| Trait |
作用 |
绑定功能 |
Clone |
显式深拷贝 |
.clone() |
Copy |
隐式按位拷贝 |
赋值自动拷贝 |
Drop |
析构逻辑 |
离开作用域自动调用 |
Display |
用户友好输出 |
{} 打印 |
Debug |
调试输出 |
{:?} 打印 |
1 2 3 4 5
| impl Drop for Resource { fn drop(&mut self) { } }
|
7. collection - 集合类型
Vec 动态数组
1 2 3 4 5
| let mut v = vec ![1, 2, 3]; v.push(4); let last = v.pop(); v.get(2);
|
String 字符串
1 2 3 4
| let mut s = String::from("hello"); s.push_str(" world"); s.replace("hello", "hi"); "hello".to_string();
|
闭包语法
|参数| 表达式,类似 Lambda:
1 2 3
| |x| x * 2 |x, y| x + y |x| { x * 2; x }
|
迭代器与 collect
collect() 收集迭代器元素,必须标注类型(因为可返回多种集合):
1 2 3 4 5 6 7 8 9
| let doubled: Vec<i32> = v.iter().map(|x| x * 2).collect();
let result = iter.collect::<Vec<i32>>(); let result = iter.collect::<Vec<_>>();
println!("{:?}", a.intersection(&b).collect::<Vec<_>>());
|
链式调用
1 2 3 4 5 6 7
| let result: Vec<i32> = v.iter() .filter(|x| *x % 2 == 0) .map(|x| x * 3) .take(2) .collect();
let sum = (1..=10).fold(0, |acc, x| acc + x);
|
HashSet 集合操作
1 2 3 4 5 6 7
| let a: HashSet<i32> = vec ![1, 2, 3].into_iter().collect(); let b: HashSet<i32> = vec ![2, 3, 4].into_iter().collect(); a.intersection(&b); a.union(&b); a.difference(&b);
|
HashMap
1 2 3
| let mut map: HashMap<String, i32> = HashMap::new(); map.insert("a".to_string(), 1); map.entry("b").or_insert(0);
|