Rust 程序设计语言 - 完整知识体系
第一部分:基础入门
1. 安装与环境配置
Rustup 安装
# Linux/macOS
curl --proto '=https' --tlsv1.2 https://sh.rustup.rs -sSf | sh
# Windows: 访问 https://www.rust-lang.org/install.html
验证安装
rustc --version # 查看编译器版本
cargo --version # 查看包管理工具版本
更新与卸载
rustup update # 更新Rust
rustup self uninstall # 卸载Rust
rustup doc # 打开本地文档
2. Hello World 程序
fn main() {
println!("Hello, world!");
}
编译与运行
rustc main.rs # 编译
./main # 运行(Windows: .\main.exe)
关键点:
-
main函数是程序入口点 -
println!是宏(macro),注意感叹号 -
Rust源文件以
.rs结尾 -
语句以分号
;结束
3. Cargo 项目管理
创建项目
cargo new project_name # 创建新项目
cargo init # 初始化现有目录
项目结构
my_project/
├── Cargo.toml # 项目配置文件
├── Cargo.lock # 依赖锁定文件
└── src/
└── main.rs # 源代码
常用命令
cargo build # 构建项目(debug模式)
cargo build --release # 发布构建(优化)
cargo run # 构建并运行
cargo check # 快速检查是否可编译(不生成可执行文件)
cargo test # 运行测试
cargo doc --open # 生成并打开文档
第二部分:核心编程概念
1. 变量与可变性
变量绑定
let x = 5; // 不可变变量(默认)
let mut y = 5; // 可变变量
y = 6; // 可以修改
常量
const MAX_POINTS: u32 = 100_000; // 必须标注类型,全大写命名
遮蔽(Shadowing)
let x = 5;
let x = x + 1; // 新变量遮蔽旧变量
{
let x = x * 2; // 在内部作用域遮蔽
println!("{}", x); // 12
}
println!("{}", x); // 6
2. 数据类型
标量类型
| 类型 | 说明 | 示例 |
|---|---|---|
| 整型 | i8, u8, i16, u16, i32, u32, i64, u64, i128, u128, isize, usize | let x: i32 = 42; |
| 浮点型 | f32, f64 | let x = 2.0; // f64 |
| 布尔型 | bool | let t = true; |
| 字符型 | char(4字节,Unicode) | let c = '😻'; |
整型溢出处理
// Debug模式: panic
// Release模式: 二进制补码回绕
let x: u8 = 255;
let y = x.wrapping_add(1); // 回绕
let z = x.checked_add(1); // 返回Option
let w = x.saturating_add(1); // 饱和处理
复合类型
元组(Tuple)
let tup: (i32, f64, u8) = (500, 6.4, 1);
let (x, y, z) = tup; // 解构
let first = tup.0; // 索引访问
let unit = (); // 单元类型
数组(Array)
let a = [1, 2, 3, 4, 5]; // 固定长度
let b: [i32; 5] = [1, 2, 3, 4, 5];
let c = [3; 5]; // [3, 3, 3, 3, 3]
let first = a[0]; // 索引访问(越界会panic)
3. 函数
函数定义
fn add(x: i32, y: i32) -> i32 {
x + y // 隐式返回(无分号)
}
fn early_return(x: i32) -> i32 {
if x < 0 {
return 0; // 提前返回
}
x
}
语句与表达式
-
语句:执行操作但不返回值(如
let x = 5;) -
表达式:计算并返回值(如
5 + 6,代码块)
let y = {
let x = 3;
x + 1 // 表达式,无分号
}; // y = 4
4. 控制流
if 表达式
let number = 6;
if number % 4 == 0 {
println!("divisible by 4");
} else if number % 3 == 0 {
println!("divisible by 3");
} else {
println!("not divisible");
}
// if 作为表达式
let result = if condition { 5 } else { 6 }; // 分支类型必须一致
循环
loop - 无限循环
let mut counter = 0;
let result = loop {
counter += 1;
if counter == 10 {
break counter * 2; // 返回值
}
};
while - 条件循环
let mut number = 3;
while number != 0 {
println!("{}!", number);
number -= 1;
}
for - 遍历集合
let a = [10, 20, 30, 40, 50];
for element in a {
println!("{}", element);
}
// 使用Range
for number in (1..4).rev() {
println!("{}!", number); // 3! 2! 1!
}
循环标签
'outer: loop {
loop {
break 'outer; // 跳出外层循环
}
}
第三部分:所有权系统
1. 所有权规则
-
Rust中每一个值都有一个所有者
-
值在任一时刻有且只有一个所有者
-
当所有者离开作用域,值被丢弃
栈与堆
-
栈:LIFO,存储固定大小数据,速度快
-
堆:存储动态大小数据,速度较慢
2. 移动与克隆
移动(Move)
let s1 = String::from("hello");
let s2 = s1; // s1被移动到s2,s1不再有效
// println!("{}", s1); // 编译错误
克隆(Clone)
let s1 = String::from("hello");
let s2 = s1.clone(); // 深拷贝
println!("{} {}", s1, s2); // 正常工作
拷贝(Copy)
let x = 5;
let y = x; // 整型实现Copy,x仍有效
实现 Copy 的类型:
-
所有整数类型(i32, u64等)
-
布尔类型 bool
-
所有浮点类型(f64等)
-
字符类型 char
-
元组(仅当所有元素都实现Copy)
3. 引用与借用
不可变引用
fn calculate_length(s: &String) -> usize {
s.len()
}
let s1 = String::from("hello");
let len = calculate_length(&s1); // 借用
可变引用
fn change(s: &mut String) {
s.push_str(", world");
}
let mut s = String::from("hello");
change(&mut s);
引用规则
-
任意时刻,只能有一个可变引用或多个不可变引用
-
引用必须始终有效
let mut s = String::from("hello");
let r1 = &s;
let r2 = &s;
// let r3 = &mut s; // 编译错误:不能同时存在不可变和可变引用
println!("{} {}", r1, r2);
4. Slice 类型
字符串Slice
let s = String::from("hello world");
let hello = &s[0..5]; // "hello"
let world = &s[6..11]; // "world"
let slice = &s[..2]; // 从开头到索引2
let slice = &s[3..]; // 从索引3到结尾
let slice = &s[..]; // 整个字符串
函数参数:优先使用 &str
fn first_word(s: &str) -> &str {
// 可以接受 &String 或 &str
}
第四部分:结构体与枚举
1. 结构体定义与实例化
定义结构体
struct User {
active: bool,
username: String,
email: String,
sign_in_count: u64,
}
实例化
let user1 = User {
active: true,
username: String::from("someusername123"),
email: String::from("someone@example.com"),
sign_in_count: 1,
};
字段初始化简写
fn build_user(email: String, username: String) -> User {
User {
active: true,
username, // 字段名与变量名相同
email,
sign_in_count: 1,
}
}
结构体更新语法
let user2 = User {
email: String::from("another@example.com"),
..user1 // 剩余字段从user1获取(注意:String会被移动)
};
元组结构体
struct Color(i32, i32, i32);
struct Point(i32, i32, i32);
let black = Color(0, 0, 0);
let origin = Point(0, 0, 0);
类单元结构体
struct AlwaysEqual;
let subject = AlwaysEqual;
2. 方法语法
定义方法
#[derive(Debug)]
struct Rectangle {
width: u32,
height: u32,
}
impl Rectangle {
// 方法:&self借用
fn area(&self) -> u32 {
self.width * self.height
}
// 可变借用
fn set_width(&mut self, width: u32) {
self.width = width;
}
// 获取所有权(少见)
fn into_string(self) -> String {
format!("{}x{}", self.width, self.height)
}
}
let rect = Rectangle { width: 30, height: 50 };
println!("Area: {}", rect.area());
关联函数
impl Rectangle {
// 关联函数(不是方法)
fn square(size: u32) -> Self {
Self { width: size, height: size }
}
}
let sq = Rectangle::square(3);
多个impl块
impl Rectangle {
fn area(&self) -> u32 { /* ... */ }
}
impl Rectangle {
fn can_hold(&self, other: &Rectangle) -> bool { /* ... */ }
}
3. 枚举
定义枚举
enum IpAddrKind {
V4,
V6,
}
// 关联数据
enum IpAddr {
V4(u8, u8, u8, u8),
V6(String),
}
enum Message {
Quit,
Move { x: i32, y: i32 }, // 结构体变体
Write(String),
ChangeColor(i32, i32, i32),
}
枚举方法
impl Message {
fn call(&self) {
// 方法体
}
}
4. Option 枚举
enum Option<T> {
Some(T),
None,
}
let some_number = Some(5);
let some_char = Some('e');
let absent_number: Option<i32> = None;
// 不能将Option与普通类型直接运算
let x: i8 = 5;
let y: Option<i8> = Some(5);
// let sum = x + y; // 编译错误
第五部分:模式匹配
1. match 表达式
enum Coin {
Penny,
Nickel,
Dime,
Quarter(UsState),
}
fn value_in_cents(coin: Coin) -> u8 {
match coin {
Coin::Penny => 1,
Coin::Nickel => 5,
Coin::Dime => 10,
Coin::Quarter(state) => {
println!("State quarter from {:?}!", state);
25
}
}
}
匹配 Option
fn plus_one(x: Option<i32>) -> Option<i32> {
match x {
None => None,
Some(i) => Some(i + 1),
}
}
匹配必须穷尽
// 编译错误:没有处理None
match x {
Some(i) => Some(i + 1),
}
通配模式
let dice_roll = 9;
match dice_roll {
3 => add_fancy_hat(),
7 => remove_fancy_hat(),
other => move_player(other), // 通配变量
// _ => (), // 忽略值
}
2. if let 与 let else
// if let - 只关心一种模式
let config_max = Some(3u8);
if let Some(max) = config_max {
println!("Maximum is {}", max);
}
// if let else
if let Coin::Quarter(state) = coin {
println!("State quarter from {:?}!", state);
} else {
count += 1;
}
// let else - 模式匹配失败时提前返回
let Some(value) = optional_value else {
return None;
};
第六部分:模块系统
1. 包与Crate
-
Crate:编译的最小单元,可以是二进制或库
-
Package:包含Cargo.toml,可包含多个Crate
Crate根文件
-
src/main.rs:二进制crate根 -
src/lib.rs:库crate根 -
src/bin/*.rs:多个二进制crate
2. 模块定义
// src/lib.rs
mod front_of_house {
pub mod hosting {
pub fn add_to_waitlist() {}
fn seat_at_table() {}
}
mod serving {
fn take_order() {}
}
}
模块树
crate
└── front_of_house
├── hosting
│ ├── add_to_waitlist
│ └── seat_at_table
└── serving
├── take_order
└── serve_order
3. 路径
// 绝对路径(从crate根开始)
crate::front_of_house::hosting::add_to_waitlist();
// 相对路径
front_of_house::hosting::add_to_waitlist();
// super路径(父模块)
super::deliver_order();
4. pub 关键字
// 模块公有
pub mod hosting {
// 函数公有
pub fn add_to_waitlist() {}
}
// 结构体公有但字段私有
pub struct Breakfast {
pub toast: String, // 公有字段
seasonal_fruit: String, // 私有字段
}
// 枚举公有则所有变体公有
pub enum Appetizer {
Soup,
Salad,
}
5. use 关键字
// 导入模块
use crate::front_of_house::hosting;
// 导入函数(习惯:导入父模块)
use crate::front_of_house::hosting::add_to_waitlist;
// 重命名
use std::io::Result as IoResult;
// 重导出
pub use crate::front_of_house::hosting;
// 嵌套路径
use std::{cmp::Ordering, io};
use std::io::{self, Write};
// Glob导入
use std::collections::*;
6. 模块文件拆分
src/
├── lib.rs
├── front_of_house.rs
└── front_of_house/
└── hosting.rs
// src/lib.rs
mod front_of_house;
pub use crate::front_of_house::hosting;
// src/front_of_house.rs
pub mod hosting;
// src/front_of_house/hosting.rs
pub fn add_to_waitlist() {}
第七部分:常见集合
1. Vector
创建
let v: Vec<i32> = Vec::new();
let v = vec![1, 2, 3];
更新
let mut v = Vec::new();
v.push(5);
v.push(6);
读取
let v = vec![1, 2, 3, 4, 5];
let third: &i32 = &v[2]; // 索引(越界panic)
let third: Option<&i32> = v.get(2); // 安全访问
// 遍历
for i in &v {
println!("{}", i);
}
// 可变遍历
for i in &mut v {
*i += 50;
}
存储不同类型(使用枚举)
enum SpreadsheetCell {
Int(i32),
Float(f64),
Text(String),
}
let row = vec![
SpreadsheetCell::Int(3),
SpreadsheetCell::Text(String::from("blue")),
];
2. 字符串
创建
let mut s = String::new();
let s = "initial contents".to_string();
let s = String::from("initial contents");
更新
let mut s = String::from("foo");
s.push_str("bar"); // 追加字符串
s.push('l'); // 追加字符
// + 运算符
let s1 = String::from("Hello, ");
let s2 = String::from("world!");
let s3 = s1 + &s2; // s1被移动
// format! 宏
let s = format!("{}-{}-{}", s1, s2, s3);
索引与遍历
// Rust字符串不支持索引(UTF-8编码)
let hello = "Здравствуйте";
let s = &hello[0..4]; // 按字节切片
// 遍历字符
for c in "Зд".chars() {
println!("{}", c);
}
// 遍历字节
for b in "Зд".bytes() {
println!("{}", b);
}
3. HashMap
创建
use std::collections::HashMap;
let mut scores = HashMap::new();
scores.insert(String::from("Blue"), 10);
scores.insert(String::from("Yellow"), 50);
读取
let team_name = String::from("Blue");
let score = scores.get(&team_name).copied().unwrap_or(0);
// 遍历
for (key, value) in &scores {
println!("{}: {}", key, value);
}
更新
// 覆盖
scores.insert(String::from("Blue"), 25);
// 仅当键不存在时插入
scores.entry(String::from("Yellow")).or_insert(50);
// 根据旧值更新
let text = "hello world wonderful world";
let mut map = HashMap::new();
for word in text.split_whitespace() {
let count = map.entry(word).or_insert(0);
*count += 1;
}
所有权
let field_name = String::from("Favorite color");
let field_value = String::from("Blue");
let mut map = HashMap::new();
map.insert(field_name, field_value);
// field_name和field_value不再有效
第八部分:错误处理
1. panic! 不可恢复错误
显式panic
panic!("crash and burn");
调试backtrace
RUST_BACKTRACE=1 cargo run
panic行为配置
[profile.release]
panic = 'abort' # 使用终止而非展开
2. Result 可恢复错误
Result类型
enum Result<T, E> {
Ok(T),
Err(E),
}
处理Result
use std::fs::File;
use std::io::ErrorKind;
let greeting_file_result = File::open("hello.txt");
let greeting_file = match greeting_file_result {
Ok(file) => file,
Err(error) => match error.kind() {
ErrorKind::NotFound => match File::create("hello.txt") {
Ok(fc) => fc,
Err(e) => panic!("Problem creating the file: {:?}", e),
},
other_error => {
panic!("Problem opening the file: {:?}", other_error);
}
},
};
快捷方法
let file = File::open("hello.txt").unwrap(); // 失败时panic
let file = File::open("hello.txt")
.expect("Failed to open hello.txt"); // 自定义panic消息
3. 传播错误(? 运算符)
手动传播
fn read_username_from_file() -> Result<String, io::Error> {
let mut username_file = match File::open("hello.txt") {
Ok(file) => file,
Err(e) => return Err(e),
};
let mut username = String::new();
match username_file.read_to_string(&mut username) {
Ok(_) => Ok(username),
Err(e) => Err(e),
}
}
使用 ? 运算符
fn read_username_from_file() -> Result<String, io::Error> {
let mut username = String::new();
File::open("hello.txt")?.read_to_string(&mut username)?;
Ok(username)
}
// 更简洁
fn read_username_from_file() -> Result<String, io::Error> {
fs::read_to_string("hello.txt")
}
? 与 Option
fn last_char_of_first_line(text: &str) -> Option<char> {
text.lines().next()?.chars().last()
}
main函数返回Result
fn main() -> Result<(), Box<dyn Error>> {
let file = File::open("hello.txt")?;
Ok(())
}
4. 何时使用 panic vs Result
-
panic:示例、原型、测试、已知情况不可能失败
-
Result:可能的错误,让调用者决定处理方式
自定义类型验证
pub struct Guess {
value: i32,
}
impl Guess {
pub fn new(value: i32) -> Guess {
if value < 1 || value > 100 {
panic!("Guess value must be between 1 and 100, got {}.", value);
}
Guess { value }
}
pub fn value(&self) -> i32 {
self.value
}
}
第九部分:泛型、Trait与生命周期
1. 泛型
函数定义
fn largest<T>(list: &[T]) -> &T {
let mut largest = &list[0];
for item in list {
if item > largest { // 需要T实现PartialOrd
largest = item;
}
}
largest
}
结构体定义
struct Point<T, U> {
x: T,
y: U,
}
let both_integer = Point { x: 5, y: 10 };
let integer_and_float = Point { x: 5, y: 4.0 };
枚举定义
enum Result<T, E> {
Ok(T),
Err(E),
}
方法定义
impl<T> Point<T> {
fn x(&self) -> &T {
&self.x
}
}
// 针对特定类型
impl Point<f32> {
fn distance_from_origin(&self) -> f32 {
(self.x.powi(2) + self.y.powi(2)).sqrt()
}
}
泛型性能:单态化(Monomorphization),无运行时开销
2. Trait
定义Trait
pub trait Summary {
fn summarize(&self) -> String;
}
实现Trait
pub struct NewsArticle {
pub headline: String,
pub location: String,
pub author: String,
pub content: String,
}
impl Summary for NewsArticle {
fn summarize(&self) -> String {
format!("{}, by {} ({})", self.headline, self.author, self.location)
}
}
默认实现
pub trait Summary {
fn summarize(&self) -> String {
String::from("(Read more...)")
}
}
pub trait Summary {
fn summarize_author(&self) -> String;
fn summarize(&self) -> String {
format!("(Read more from {}...)", self.summarize_author())
}
}
Trait作为参数
// impl Trait语法
pub fn notify(item: &impl Summary) {
println!("Breaking news! {}", item.summarize());
}
// Trait Bound语法
pub fn notify<T: Summary>(item: &T) {
println!("Breaking news! {}", item.summarize());
}
// 多个Trait
pub fn notify(item: &(impl Summary + Display)) {}
// 或
pub fn notify<T: Summary + Display>(item: &T) {}
// where从句
fn some_function<T, U>(t: &T, u: &U) -> i32
where
T: Display + Clone,
U: Clone + Debug,
{
// ...
}
返回实现Trait的类型
fn returns_summarizable() -> impl Summary {
NewsArticle { /* ... */ }
}
有条件实现方法
use std::fmt::Display;
impl<T: Display + PartialOrd> Pair<T> {
fn cmp_display(&self) {
if self.x >= self.y {
println!("The largest member is x = {}", self.x);
} else {
println!("The largest member is y = {}", self.y);
}
}
}
3. 生命周期
生命周期注解语法
&i32 // 引用
&'a i32 // 带有显式生命周期的引用
&'a mut i32 // 带有显式生命周期的可变引用
函数签名中的生命周期
fn longest<'a>(x: &'a str, y: &'a str) -> &'a str {
if x.len() > y.len() { x } else { y }
}
结构体中的生命周期
struct ImportantExcerpt<'a> {
part: &'a str,
}
生命周期省略规则
-
每个引用参数都有自己的生命周期参数
-
如果只有一个输入生命周期,输出生命周期与其相同
-
如果有
&self或&mut self,输出生命周期为self的生命周期
静态生命周期
let s: &'static str = "I have a static lifetime.";
结合泛型、Trait和生命周期
use std::fmt::Display;
fn longest_with_an_announcement<'a, T>(
x: &'a str,
y: &'a str,
ann: T,
) -> &'a str
where
T: Display,
{
println!("Announcement! {}", ann);
if x.len() > y.len() { x } else { y }
}
第十部分:智能指针
1. Box<T>
用途:堆上分配、递归类型、trait对象
let b = Box::new(5);
println!("b = {}", b);
// 递归类型
enum List {
Cons(i32, Box<List>),
Nil,
}
let list = Cons(1, Box::new(Cons(2, Box::new(Cons(3, Box::new(Nil))))));
2. Deref Trait
实现Deref
use std::ops::Deref;
struct MyBox<T>(T);
impl<T> Deref for MyBox<T> {
type Target = T;
fn deref(&self) -> &Self::Target {
&self.0
}
}
let x = 5;
let y = MyBox::new(x);
assert_eq!(5, *y); // 解引用
Deref强制转换
fn hello(name: &str) {
println!("Hello, {}!", name);
}
let m = MyBox::new(String::from("Rust"));
hello(&m); // &MyBox<String> -> &String -> &str
3. Drop Trait
struct CustomSmartPointer {
data: String,
}
impl Drop for CustomSmartPointer {
fn drop(&mut self) {
println!("Dropping with data `{}`!", self.data);
}
}
let c = CustomSmartPointer { data: String::from("my stuff") };
drop(c); // 手动提前释放
4. Rc<T> - 引用计数
用途:单线程共享所有权
use std::rc::Rc;
enum List {
Cons(i32, Rc<List>),
Nil,
}
let a = Rc::new(Cons(5, Rc::new(Cons(10, Rc::new(Nil)))));
let b = Cons(3, Rc::clone(&a));
let c = Cons(4, Rc::clone(&a));
// 查看引用计数
println!("count = {}", Rc::strong_count(&a));
5. RefCell<T> - 内部可变性
用途:运行时借用检查
use std::cell::RefCell;
let x = RefCell::new(5);
{
let mut y = x.borrow_mut(); // 可变借用
*y += 1;
}
let z = x.borrow(); // 不可变借用
println!("{}", z);
运行时panic
// 违反借用规则会panic
let mut one_borrow = x.borrow_mut();
let mut two_borrow = x.borrow_mut(); // 运行时panic
6. 组合使用
Rc<RefCell<T>>
use std::cell::RefCell;
use std::rc::Rc;
let value = Rc::new(RefCell::new(5));
let a = Rc::new(Cons(Rc::clone(&value), Rc::new(Nil)));
let b = Cons(Rc::new(RefCell::new(3)), Rc::clone(&a));
*value.borrow_mut() += 10; // 修改共享数据
7. 引用循环与 Weak<T>
引用循环问题
use std::cell::RefCell;
use std::rc::Rc;
#[derive(Debug)]
enum List {
Cons(i32, RefCell<Rc<List>>),
Nil,
}
// 可能导致内存泄漏
使用 Weak 打破循环
use std::rc::{Rc, Weak};
#[derive(Debug)]
struct Node {
value: i32,
parent: RefCell<Weak<Node>>,
children: RefCell<Vec<Rc<Node>>>,
}
let leaf = Rc::new(Node {
value: 3,
parent: RefCell::new(Weak::new()),
children: RefCell::new(vec![]),
});
let branch = Rc::new(Node {
value: 5,
parent: RefCell::new(Weak::new()),
children: RefCell::new(vec![Rc::clone(&leaf)]),
});
*leaf.parent.borrow_mut() = Rc::downgrade(&branch);
// 升级弱引用
let parent = leaf.parent.borrow().upgrade(); // Option<Rc<Node>>
第十一部分:并发
1. 线程
创建线程
use std::thread;
use std::time::Duration;
let handle = thread::spawn(|| {
for i in 1..10 {
println!("hi number {} from spawned thread!", i);
thread::sleep(Duration::from_millis(1));
}
});
for i in 1..5 {
println!("hi number {} from main thread!", i);
thread::sleep(Duration::from_millis(1));
}
handle.join().unwrap(); // 等待线程结束
move闭包
let v = vec![1, 2, 3];
let handle = thread::spawn(move || {
println!("Here's a vector: {:?}", v);
});
handle.join().unwrap();
2. 消息传递
使用channel
use std::sync::mpsc;
use std::thread;
let (tx, rx) = mpsc::channel();
thread::spawn(move || {
let val = String::from("hi");
tx.send(val).unwrap();
});
let received = rx.recv().unwrap();
println!("Got: {}", received);
多生产者
let (tx, rx) = mpsc::channel();
let tx1 = tx.clone();
// 两个线程发送消息
// ...
for received in rx {
println!("Got: {}", received);
}
3. 共享状态
Mutex
use std::sync::Mutex;
let m = Mutex::new(5);
{
let mut num = m.lock().unwrap();
*num = 6;
}
println!("m = {:?}", m);
Arc - 原子引用计数
use std::sync::{Arc, Mutex};
use std::thread;
let counter = Arc::new(Mutex::new(0));
let mut handles = vec![];
for _ in 0..10 {
let counter = Arc::clone(&counter);
let handle = thread::spawn(move || {
let mut num = counter.lock().unwrap();
*num += 1;
});
handles.push(handle);
}
for handle in handles {
handle.join().unwrap();
}
println!("Result: {}", *counter.lock().unwrap());
组合选择指南
| 场景 | 单线程 | 多线程 |
|---|---|---|
| 堆分配 | Box<T> |
Box<T> |
| 共享只读 | Rc<T> |
Arc<T> |
| 共享可变 | Rc<RefCell<T>> |
Arc<Mutex<T>> 或 Arc<RwLock<T>> |
| 按值替换 | Cell<T> |
不适用 |
| 防止循环 | Weak<T> |
Weak<T>(配合Arc) |
4. Send 与 Sync Trait
-
Send:可在线程间转移所有权
-
Sync:可在线程间安全共享引用
Rc<T> 不是 Send,RefCell<T> 不是 Sync。
第十二部分:Async 与 Await
1. Future 基础
use trpl::Html;
async fn page_title(url: &str) -> Option<String> {
let response = trpl::get(url).await;
let response_text = response.text().await;
Html::parse(&response_text)
.select_first("title")
.map(|title| title.inner_html())
}
Future trait
trait Future {
type Output;
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output>;
}
enum Poll<T> {
Ready(T),
Pending,
}
2. 运行时
fn main() {
trpl::run(async {
let title = page_title("https://example.com").await;
println!("Title: {:?}", title);
});
}
3. 并发执行
join
let fut1 = async { /* ... */ };
let fut2 = async { /* ... */ };
let (result1, result2) = trpl::join(fut1, fut2).await;
join! 宏
let (r1, r2, r3) = trpl::join!(fut1, fut2, fut3).await;
join_all
let futures = vec![fut1, fut2, fut3];
let results = trpl::join_all(futures).await;
race
match trpl::race(fut1, fut2).await {
Either::Left(result) => println!("fut1 won: {}", result),
Either::Right(result) => println!("fut2 won: {}", result),
}
4. Pin 与 Unpin
-
Pin:防止值在内存中移动
-
Unpin:可安全移动的类型
let pinned = pin!(async { /* ... */ });
5. Stream
创建Stream
use trpl::StreamExt;
let stream = trpl::stream_from_iter(vec![1, 2, 3]);
while let Some(value) = stream.next().await {
println!("{}", value);
}
Stream操作
let filtered = stream.filter(|x| x % 2 == 0);
let mapped = stream.map(|x| x * 2);
let throttled = stream.throttle(Duration::from_millis(100));
let merged = stream1.merge(stream2);
第十三部分:测试
1. 单元测试
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn exploration() {
let result = add(2, 2);
assert_eq!(result, 4);
}
#[test]
fn another() {
panic!("Make this test fail");
}
}
断言宏
assert!(condition); // 条件为true时通过
assert_eq!(left, right); // 相等时通过
assert_ne!(left, right); // 不相等时通过
// 自定义错误信息
assert!(
result.contains("Carol"),
"Greeting did not contain name, value was `{}`",
result
);
2. 测试 panic
#[test]
#[should_panic(expected = "less than or equal to 100")]
fn greater_than_100() {
Guess::new(200);
}
3. 使用 Result 的测试
#[test]
fn it_works() -> Result<(), String> {
if 2 + 2 == 4 {
Ok(())
} else {
Err(String::from("two plus two does not equal four"))
}
}
4. 控制测试运行
cargo test -- --test-threads=1 # 单线程运行
cargo test -- --show-output # 显示println输出
cargo test test_name # 运行特定测试
cargo test prefix_ # 运行匹配前缀的测试
cargo test -- --ignored # 运行忽略的测试
cargo test -- --include-ignored # 运行所有测试
5. 集成测试
my_project/
├── src/
│ └── lib.rs
└── tests/
├── integration_test.rs
└── common/
└── mod.rs
// tests/integration_test.rs
use my_lib::add_two;
#[test]
fn it_adds_two() {
assert_eq!(add_two(2), 4);
}
第十四部分:高级特性
1. 不安全Rust
不安全超能力
-
解引用裸指针
-
调用不安全函数
-
访问/修改可变静态变量
-
实现不安全trait
-
访问union字段
裸指针
let mut num = 5;
let r1 = &raw const num;
let r2 = &raw mut num;
unsafe {
println!("r1 is: {}", *r1);
println!("r2 is: {}", *r2);
}
调用不安全函数
unsafe fn dangerous() {}
unsafe {
dangerous();
}
安全抽象示例
use std::slice;
fn split_at_mut(values: &mut [i32], mid: usize) -> (&mut [i32], &mut [i32]) {
let len = values.len();
let ptr = values.as_mut_ptr();
assert!(mid <= len);
unsafe {
(
slice::from_raw_parts_mut(ptr, mid),
slice::from_raw_parts_mut(ptr.add(mid), len - mid),
)
}
}
2. 高级Trait
关联类型
pub trait Iterator {
type Item;
fn next(&mut self) -> Option<Self::Item>;
}
默认泛型参数
use std::ops::Add;
trait Add<Rhs=Self> {
type Output;
fn add(self, rhs: Rhs) -> Self::Output;
}
完全限定语法
// 消除同名方法歧义
Pilot::fly(&person);
Wizard::fly(&person);
<Dog as Animal>::baby_name()
超Trait
trait OutlinePrint: fmt::Display {
fn outline_print(&self) {
let output = self.to_string();
// ...
}
}
3. 类型别名
type Kilometers = i32;
type Thunk = Box<dyn Fn() + Send + 'static>;
// 类型别名与Result
type Result<T> = std::result::Result<T, std::io::Error>;
4. Never类型
fn bar() -> ! {
panic!("never returns");
}
5. 动态大小类型
Sized Trait
fn generic<T: ?Sized>(t: &T) {
// T可以是Sized或非Sized
}
6. 函数指针
fn add_one(x: i32) -> i32 {
x + 1
}
fn do_twice(f: fn(i32) -> i32, arg: i32) -> i32 {
f(arg) + f(arg)
}
let answer = do_twice(add_one, 5);
7. 返回闭包
fn returns_closure() -> impl Fn(i32) -> i32 {
|x| x + 1
}
fn returns_closure_boxed() -> Box<dyn Fn(i32) -> i32> {
Box::new(|x| x + 1)
}
8. 宏
声明宏
#[macro_export]
macro_rules! vec {
( $( $x:expr ),* ) => {
{
let mut temp_vec = Vec::new();
$(
temp_vec.push($x);
)*
temp_vec
}
};
}
过程宏 - 自定义derive
use proc_macro::TokenStream;
use quote::quote;
use syn;
#[proc_macro_derive(HelloMacro)]
pub fn hello_macro_derive(input: TokenStream) -> TokenStream {
let ast = syn::parse(input).unwrap();
impl_hello_macro(&ast)
}
fn impl_hello_macro(ast: &syn::DeriveInput) -> TokenStream {
let name = &ast.ident;
let gen = quote! {
impl HelloMacro for #name {
fn hello_macro() {
println!("Hello, Macro! My name is {}!", stringify!(#name));
}
}
};
gen.into()
}
附录:常用代码片段
文件读写
use std::fs;
use std::io::{self, BufRead, BufReader, Write};
// 读取整个文件
let contents = fs::read_to_string("file.txt")?;
// 读取到字符串(推荐)
fn read_file(path: &str) -> io::Result<String> {
fs::read_to_string(path)
}
// 按行读取
let file = File::open("file.txt")?;
let reader = BufReader::new(file);
for line in reader.lines() {
let line = line?;
println!("{}", line);
}
// 写入文件
fs::write("output.txt", "content")?;
命令行参数
use std::env;
fn main() {
let args: Vec<String> = env::args().collect();
if args.len() < 2 {
eprintln!("Usage: program <arg>");
std::process::exit(1);
}
let query = &args[1];
let file_path = &args[2];
}
错误处理模式
// 文件操作
let file = File::open("file.txt")
.unwrap_or_else(|err| {
eprintln!("Failed to open file: {}", err);
std::process::exit(1);
});
// 传播错误
fn process_data() -> Result<String, io::Error> {
let content = fs::read_to_string("file.txt")?;
Ok(content.trim().to_string())
}
// 自定义错误
#[derive(Debug, thiserror::Error)]
pub enum MyError {
#[error("IO error: {0}")]
Io(#[from] io::Error),
#[error("Parse error: {0}")]
Parse(String),
}
迭代器操作
let numbers = vec![1, 2, 3, 4, 5];
// 常见迭代器方法
numbers.iter().map(|x| x * 2); // 转换
numbers.iter().filter(|x| x % 2 == 0); // 过滤
numbers.iter().take(3); // 取前N个
numbers.iter().skip(2); // 跳过N个
numbers.iter().any(|x| x > 3); // 任意匹配
numbers.iter().all(|x| x > 0); // 全部匹配
numbers.iter().find(|x| x == 3); // 查找
numbers.iter().fold(0, |acc, x| acc + x); // 折叠
numbers.iter().collect::<Vec<_>>(); // 收集
更多推荐

所有评论(0)