rust 从零单排 之 一战到底

16 阅读31分钟

Rust 语法详解 - 白话版

写给想学 Rust 的朋友,尽量用大白话把概念讲清楚,配合大量代码示例。


目录

  1. 为什么 Rust 这么难?
  2. 安装与 Hello World
  3. 变量与可变性
  4. 基本数据类型
  5. 函数
  6. 控制流
  7. 所有权 - Rust 的灵魂
  8. 引用与借用
  9. 切片
  10. 结构体
  11. 枚举与模式匹配
  12. Option 和 Result - 没有 Null 的世界
  13. 错误处理
  14. 泛型
  15. Trait - Rust 的接口
  16. 生命周期
  17. 闭包
  18. 迭代器
  19. 模块系统
  20. 常用集合
  21. 智能指针
  22. 并发编程
  23. 常见陷阱与技巧

为什么 Rust 这么难?

Rust 难,主要难在这几点:

  1. 所有权系统 - 这是 Rust 独有的,其他语言没有
  2. 借用检查器 - 编译器会盯着你的引用,不让你乱来
  3. 生命周期 - 告诉编译器引用能活多久

但正是这些"难"的东西,让 Rust 写出来的程序没有空指针异常没有数据竞争内存安全


安装与 Hello World

安装

# Linux/macOS
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh

# 验证安装
rustc --version
cargo --version

Hello World

// main.rs
fn main() {
    println!("Hello, World!");  // println! 是宏,不是函数,所以有感叹号
}
# 编译运行
rustc main.rs
./main

# 或者用 cargo(推荐)
cargo new hello_world
cd hello_world
cargo run

Cargo 常用命令

cargo new project_name    # 创建新项目
cargo build              # 编译(debug 模式)
cargo build --release    # 编译(release 模式,优化更多)
cargo run                # 编译并运行
cargo check              # 只检查错误,不生成二进制(快)
cargo test               # 运行测试
cargo doc --open         # 生成并打开文档

变量与可变性

默认不可变

Rust 的变量默认是不可变的,这是为了安全。

fn main() {
    let x = 5;
    println!("x = {}", x);
    
    // x = 6;  // 错误!不能修改不可变变量
}

用 mut 让变量可变

fn main() {
    let mut x = 5;  // 加上 mut 就可以改了
    println!("x = {}", x);
    
    x = 6;  // 没问题
    println!("x = {}", x);
}

变量遮蔽(Shadowing)

可以声明同名变量,新变量会遮蔽旧变量

fn main() {
    let x = 5;
    let x = x + 1;  // 遮蔽,x 现在是 6
    let x = x * 2;  // 再遮蔽,x 现在是 12
    
    println!("x = {}", x);  // 输出 12
    
    // 甚至可以改变类型!
    let spaces = "   ";      // 字符串
    let spaces = spaces.len(); // 变成数字,这在 mut 做不到
}

常量 vs 变量

// 常量:必须注明类型,必须在编译时就知道值
const MAX_POINTS: u32 = 100_000;  // 下划线增加可读性

fn main() {
    // 常量不能遮蔽,不能被修改,不能在运行时计算
    println!("Max points: {}", MAX_POINTS);
}

基本数据类型

整数类型

长度有符号无符号
8位i8u8
16位i16u16
32位i32u32
64位i64u64
128位i128u128
平台isizeusize
fn main() {
    let a: i32 = -100;      // 有符号 32 位,默认类型
    let b: u8 = 255;        // 无符号 8 位,0-255
    let c = 98_222;         // 下划线增加可读性
    let d = 0xff;           // 十六进制
    let e = 0o77;           // 八进制
    let f = 0b1111_0000;    // 二进制
    
    // 整数溢出(debug 模式会 panic,release 会回绕)
    // let overflow: u8 = 256;  // 错误!u8 最大是 255
}

浮点类型

fn main() {
    let x = 2.0;      // f64,默认类型,精度更高
    let y: f32 = 3.0; // f32
    
    // 浮点数运算
    let sum = x + 5.0;
    let diff = x - 1.0;
    let product = x * 3.0;
    let quotient = x / 2.0;
    let remainder = x % 2.0;
}

布尔类型

fn main() {
    let t = true;
    let f: bool = false;
    
    // 常用于条件判断
    if t {
        println!("是真的!");
    }
}

字符类型

fn main() {
    let c = 'z';
    let z = 'ℤ';
    let heart_eyed_cat = '😻';
    let chinese = '中';
    
    // char 是 Unicode 字符,占 4 字节
    println!("{} {} {} {}", c, z, heart_eyed_cat, chinese);
}

元组

fn main() {
    // 创建元组
    let tup: (i32, f64, u8) = (500, 6.4, 1);
    
    // 解构
    let (x, y, z) = tup;
    println!("y = {}", y);
    
    // 索引访问
    let five_hundred = tup.0;
    let six_point_four = tup.1;
    let one = tup.2;
}

数组

fn main() {
    // 固定长度,栈上分配
    let arr = [1, 2, 3, 4, 5];
    
    // 指定类型和长度
    let arr2: [i32; 5] = [1, 2, 3, 4, 5];
    
    // 重复初始化:[3, 3, 3, 3, 3]
    let arr3 = [3; 5];
    
    // 访问元素
    let first = arr[0];
    let second = arr[1];
    
    // 越界会 panic!
    // let out_of_bounds = arr[100];  // 运行时错误
}

函数

基本语法

fn main() {
    say_hello();
    greet("世界");
    
    let sum = add(5, 3);
    println!("5 + 3 = {}", sum);
}

// 无返回值
fn say_hello() {
    println!("你好!");
}

// 有参数
fn greet(name: &str) {
    println!("你好,{}!", name);
}

// 有返回值(注意没有分号的最后一行)
fn add(a: i32, b: i32) -> i32 {
    a + b  // 这是返回值,没有分号!
    // 等价于: return a + b;
}

// 提前返回
fn abs(x: i32) -> i32 {
    if x < 0 {
        return -x;  // 提前返回,有分号
    }
    x  // 正常返回,无分号
}

语句 vs 表达式

这是 Rust 的一个重要概念:

fn main() {
    // 语句:执行动作,没有返回值
    let x = 5;  // 这是一个语句
    
    // 表达式:有返回值
    let y = {
        let x = 3;
        x + 1  // 表达式,没有分号,返回 4
    };
    
    println!("y = {}", y);  // y = 4
    
    // if 也是表达式!
    let condition = true;
    let number = if condition { 5 } else { 6 };
    println!("number = {}", number);
}

控制流

if 表达式

fn main() {
    let number = 7;
    
    // 基本 if
    if number < 5 {
        println!("小于 5");
    } else if number < 10 {
        println!("小于 10 但大于等于 5");
    } else {
        println!("大于等于 10");
    }
    
    // if 作为表达式(所有分支必须返回相同类型)
    let result = if number % 2 == 0 {
        "偶数"
    } else {
        "奇数"
    };
    println!("{} 是 {}", number, result);
}

loop 循环

fn main() {
    let mut count = 0;
    
    // 无限循环
    let result = loop {
        count += 1;
        
        if count == 10 {
            break count * 2;  // 可以返回值!
        }
    };
    
    println!("结果: {}", result);  // 20
    
    // 循环标签(嵌套循环时很有用)
    let mut remaining = 10;
    
    'outer: loop {
        println!("外层循环");
        
        loop {
            remaining -= 1;
            if remaining == 5 {
                break 'outer;  // 直接跳出外层循环
            }
        }
    }
    
    println!("结束");
}

while 循环

fn main() {
    let mut number = 3;
    
    while number != 0 {
        println!("倒计时: {}!", number);
        number -= 1;
    }
    
    println!("发射!");
    
    // 遍历数组
    let arr = [10, 20, 30, 40, 50];
    let mut index = 0;
    
    while index < 5 {
        println!("arr[{}] = {}", index, arr[index]);
        index += 1;
    }
}

for 循环

fn main() {
    // 遍历数组(推荐方式)
    let arr = [10, 20, 30, 40, 50];
    
    for element in arr {
        println!("元素: {}", element);
    }
    
    // 范围
    for number in 1..4 {  // 1, 2, 3(不含 4)
        println!("{}", number);
    }
    
    for number in 1..=4 {  // 1, 2, 3, 4(包含 4)
        println!("{}", number);
    }
    
    // 倒计时
    for number in (1..=5).rev() {
        println!("倒计时: {}", number);
    }
    println!("发射!");
}

match 匹配

fn main() {
    let number = 7;
    
    match number {
        1 => println!("一"),
        2 | 3 | 5 | 7 => println!("质数"),
        4..=10 => println!("4 到 10 之间"),
        _ => println!("其他数字"),  // _ 是通配符
    }
    
    // match 是表达式
    let result = match number {
        1 => "一",
        2 => "二",
        _ => "其他",
    };
    
    println!("结果: {}", result);
}

if let

fn main() {
    let some_value = Some(7);
    
    // 只关心一种情况时,比 match 简洁
    if let Some(7) = some_value {
        println!("是 7!");
    }
    
    // 等价于:
    match some_value {
        Some(7) => println!("是 7!"),
        _ => (),
    }
    
    // 可以加 else
    if let Some(x) = some_value {
        println!("值是 {}", x);
    } else {
        println!("没有值");
    }
}

所有权 - Rust 的灵魂

这是 Rust 最独特、最重要的概念。理解了所有权,就理解了 Rust 的一半。

三条规则

  1. Rust 中每个值都有一个所有者(owner)
  2. 同一时刻只能有一个所有者
  3. 当所有者离开作用域,值会被丢弃(drop)

变量作用域

fn main() {
    // s 不可用
    {
        let s = "hello";  // s 可用
        
        // 使用 s
        println!("{}", s);
    }  // s 离开作用域,被丢弃
    
    // s 不可用
}

String 类型

fn main() {
    // 字符串字面量:不可变,编译时就确定
    let s1 = "hello";  // &str 类型
    
    // String 类型:可变,堆上分配
    let mut s2 = String::from("hello");
    s2.push_str(", world!");  // 可以修改
    println!("{}", s2);
    
    // 为什么 String 可以修改而 &str 不行?
    // - &str 是编译时就确定的字符串切片,存在二进制文件中
    // - String 是运行时在堆上分配的,可以动态改变
}

移动(Move)

fn main() {
    let s1 = String::from("hello");
    let s2 = s1;  // s1 的所有权移动到 s2
    
    // println!("{}", s1);  // 错误!s1 已经无效了
    println!("{}", s2);     // 正确
    
    // 为什么?因为 String 包含堆上的数据
    // 如果只是复制指针,两个变量指向同一块内存
    // 离开作用域时会 double free!
    // Rust 选择移动所有权,让 s1 失效
}

克隆(Clone)

fn main() {
    let s1 = String::from("hello");
    let s2 = s1.clone();  // 深拷贝
    
    println!("s1 = {}, s2 = {}", s1, s2);  // 两个都有效
    
    // clone 会复制堆上的数据,比较昂贵
    // 但有时你需要这样做
}

栈上的数据:复制

fn main() {
    let x = 5;
    let y = x;  // 复制,不是移动
    
    println!("x = {}, y = {}", x, y);  // 两个都有效
    
    // 为什么?因为整数存储在栈上,复制很便宜
    // 实现了 Copy trait 的类型会复制而不是移动
    // 包括:整数、浮点数、布尔值、字符、元组(如果元素都是 Copy)
}

函数与所有权

fn main() {
    let s = String::from("hello");
    takes_ownership(s);  // s 的所有权移动到函数
    
    // println!("{}", s);  // 错误!s 已经无效
    
    let x = 5;
    makes_copy(x);  // x 是 Copy 类型,所以复制
    
    println!("{}", x);  // x 仍然有效
}

fn takes_ownership(some_string: String) {
    println!("{}", some_string);
}  // some_string 离开作用域,被 drop

fn makes_copy(some_integer: i32) {
    println!("{}", some_integer);
}  // some_integer 离开作用域,但什么也不会发生(Copy)

返回值与所有权

fn main() {
    let s1 = gives_ownership();  // 函数把所有权转移给 s1
    
    let s2 = String::from("hello");
    let s3 = takes_and_gives_back(s2);  // s2 移动进函数,函数返回给 s3
    
    // println!("{}", s2);  // 错误!s2 已经无效
    println!("{}", s3);
}

fn gives_ownership() -> String {
    let some_string = String::from("hello");
    some_string  // 返回所有权给调用者
}

fn takes_and_gives_back(a_string: String) -> String {
    a_string  // 返回所有权
}

问题:太麻烦了!

fn main() {
    let s1 = String::from("hello");
    let (s2, len) = calculate_length(s1);  // 必须返回所有权...
    
    println!("'{}' 的长度是 {}", s2, len);
}

fn calculate_length(s: String) -> (String, usize) {
    let length = s.len();
    (s, length)  // 必须把 s 返回,否则调用者就用不了了
}

解决方案:引用!


引用与借用

什么是引用?

引用就像指针,但更安全。它让你借用值而不获取所有权。

fn main() {
    let s1 = String::from("hello");
    
    let len = calculate_length(&s1);  // 传递引用
    
    println!("'{}' 的长度是 {}", s1, len);  // s1 仍然有效!
}

fn calculate_length(s: &String) -> usize {  // 借用
    s.len()
}  // s 离开作用域,但不会 drop,因为它不拥有值

可变引用

fn main() {
    let mut s = String::from("hello");
    
    change(&mut s);
    
    println!("{}", s);  // hello, world
}

fn change(some_string: &mut String) {
    some_string.push_str(", world");
}

引用的规则

规则一:要么一个可变引用,要么多个不可变引用

fn main() {
    let mut s = String::from("hello");
    
    let r1 = &s;  // 不可变引用
    let r2 = &s;  // 不可变引用
    // let r3 = &mut s;  // 错误!不能同时有可变和不可变引用
    
    println!("{} {}", r1, r2);
    
    // 但是可以这样:
    let r3 = &mut s;  // 现在可以了,因为 r1, r2 已经不用了
    r3.push_str(" world");
}

规则二:引用必须始终有效(不能有悬垂引用)

fn main() {
    // let reference_to_nothing = dangle();  // 错误!
}

// 错误示例
fn dangle() -> &String {  // 返回 String 的引用
    let s = String::from("hello");
    
    &s  // 返回 s 的引用
}  // s 被 drop 了!引用指向了无效内存!

// 正确做法:返回所有权
fn no_dangle() -> String {
    let s = String::from("hello");
    s  // 返回 String,所有权转移
}

引用作用域

fn main() {
    let mut s = String::from("hello");
    
    let r1 = &s;
    let r2 = &s;
    println!("{} {}", r1, r2);
    // r1 和 r2 在这之后不再使用
    
    let r3 = &mut s;  // 现在可以了
    r3.push_str(" world");
}

切片

切片是对集合的一部分的引用。

字符串切片

fn main() {
    let s = String::from("hello world");
    
    let hello = &s[0..5];   // "hello"
    let world = &s[6..11];  // "world"
    
    println!("{} {}", hello, world);
    
    // 简写
    let hello = &s[..5];   // 从开头到索引 5
    let world = &s[6..];   // 从索引 6 到结尾
    let whole = &s[..];    // 整个字符串
    
    // 注意:字符串切片索引是按字节,不是字符!
    // 对于 UTF-8 字符串,要小心多字节字符
}

实际例子:找第一个单词

fn first_word(s: &String) -> &str {
    let bytes = s.as_bytes();
    
    for (i, &item) in bytes.iter().enumerate() {
        if item == b' ' {
            return &s[0..i];
        }
    }
    
    &s[..]
}

fn main() {
    let mut s = String::from("hello world");
    
    let word = first_word(&s);  // word 是 &str
    
    // s.clear();  // 错误!不能同时有可变和不可变引用
    
    println!("第一个单词: {}", word);
}

数组切片

fn main() {
    let a = [1, 2, 3, 4, 5];
    
    let slice = &a[1..3];  // [2, 3]
    
    println!("{:?}", slice);
}

结构体

定义和实例化

// 定义结构体
struct User {
    username: String,
    email: String,
    sign_in_count: u64,
    active: bool,
}

fn main() {
    // 创建实例
    let user1 = User {
        email: String::from("user@example.com"),
        username: String::from("user123"),
        active: true,
        sign_in_count: 1,
    };
    
    // 访问字段
    println!("用户名: {}", user1.username);
    
    // 可变实例
    let mut user2 = User {
        email: String::from("user2@example.com"),
        username: String::from("user456"),
        active: false,
        sign_in_count: 0,
    };
    
    user2.active = true;  // 修改字段
}

简写

fn build_user(email: String, username: String) -> User {
    User {
        email,    // 简写,变量名和字段名相同
        username,
        active: true,
        sign_in_count: 1,
    }
}

结构体更新语法

fn main() {
    let user1 = User {
        email: String::from("user1@example.com"),
        username: String::from("user1"),
        active: true,
        sign_in_count: 1,
    };
    
    // 从 user1 创建 user2,只修改部分字段
    let user2 = User {
        email: String::from("user2@example.com"),
        ..user1  // 其余字段从 user1 复制
    };
    
    // 注意:..user1 必须在最后
    // 注意:username 被 String::from 移动了,所以 user1.username 不能再使用
    // 但 active 和 sign_in_count 是 Copy 类型,所以 user1 还能用它们
}

元组结构体

struct Color(i32, i32, i32);
struct Point(i32, i32, i32);

fn main() {
    let black = Color(0, 0, 0);
    let origin = Point(0, 0, 0);
    
    // 它们是不同类型,不能混用
    println!("黑色: ({}, {}, {})", black.0, black.1, black.2);
}

空结构体

struct AlwaysEqual;  // 没有任何字段

fn main() {
    let subject = AlwaysEqual;
}

打印结构体

#[derive(Debug)]  // 添加这个属性
struct User {
    username: String,
    email: String,
}

fn main() {
    let user = User {
        username: String::from("user"),
        email: String::from("user@example.com"),
    };
    
    println!("{:?}", user);   // 调试格式
    println!("{:#?}", user);  // 美化的调试格式
}

方法

#[derive(Debug)]
struct Rectangle {
    width: u32,
    height: u32,
}

impl Rectangle {
    // 关联函数(类似静态方法)
    fn new(width: u32, height: u32) -> Self {
        Self { width, height }
    }
    
    // 方法(第一个参数是 self)
    fn area(&self) -> u32 {
        self.width * self.height
    }
    
    fn width(&self) -> bool {
        self.width > 0
    }
    
    // 可变方法
    fn scale(&mut self, factor: u32) {
        self.width *= factor;
        self.height *= factor;
    }
    
    // 方法可以与字段同名
    // 通常用于实现 getter
}

fn main() {
    let rect = Rectangle::new(30, 50);  // 调用关联函数
    println!("rect: {:?}", rect);
    
    println!("面积: {}", rect.area());  // 调用方法
    println!("有宽度: {}", rect.width());
    
    let mut rect2 = Rectangle::new(10, 20);
    rect2.scale(2);
    println!("放大后: {:?}", rect2);
}

枚举与模式匹配

定义枚举

enum IpAddr {
    V4,
    V6,
}

fn main() {
    let four = IpAddr::V4;
    let six = IpAddr::V6;
    
    route(four);
    route(six);
}

fn route(ip_type: IpAddr) {
    match ip_type {
        IpAddr::V4 => println!("IPv4 地址"),
        IpAddr::V6 => println!("IPv6 地址"),
    }
}

枚举存储数据

enum IpAddr {
    V4(String),
    V6(String),
}

fn main() {
    let home = IpAddr::V4(String::from("127.0.0.1"));
    let loopback = IpAddr::V6(String::from("::1"));
    
    match home {
        IpAddr::V4(ip) => println!("IPv4: {}", ip),
        IpAddr::V6(ip) => println!("IPv6: {}", ip),
    }
}

更复杂的枚举

enum Message {
    Quit,                       // 没有关联数据
    Move { x: i32, y: i32 },    // 匿名结构体
    Write(String),              // 字符串
    ChangeColor(i32, i32, i32), // 三个整数
}

impl Message {
    fn call(&self) {
        match self {
            Message::Quit => println!("退出"),
            Message::Move { x, y } => println!("移动到 ({}, {})", x, y),
            Message::Write(text) => println!("写入: {}", text),
            Message::ChangeColor(r, g, b) => println!("颜色: RGB({}, {}, {})", r, g, b),
        }
    }
}

fn main() {
    let m = Message::Write(String::from("hello"));
    m.call();
}

Option 枚举

Rust 没有 null,用 Option 表示可能不存在的值:

enum Option<T> {
    Some(T),
    None,
}

fn main() {
    let some_number = Some(5);
    let some_char = Some('e');
    let absent_number: Option<i32> = None;
    
    // 必须处理 None 的情况
    let x: Option<i32> = Some(5);
    let sum = match x {
        Some(n) => n + 1,
        None => 0,
    };
    
    println!("sum = {}", sum);
}

match 必须穷尽所有可能

fn main() {
    let number = 7;
    
    // match number {
    //     1 => println!("一"),
    //     2 => println!("二"),
    //     // 错误!没有处理其他情况
    // }
    
    // 正确:用 _ 处理其他情况
    match number {
        1 => println!("一"),
        2 => println!("二"),
        _ => println!("其他"),
    }
}

绑定值的模式

fn main() {
    let x = Some(5);
    let y = 10;
    
    match x {
        Some(50) => println!("是 50"),
        Some(y) => println!("匹配到 y = {}", y),  // 这里的 y 是新变量
        _ => println!("默认情况"),
    }
    
    println!("外部的 y = {}", y);  // y 还是 10
}

多重模式

fn main() {
    let x = 1;
    
    match x {
        1 | 2 => println!("一或二"),
        3..=5 => println!("三到五"),
        _ => println!("其他"),
    }
}

解构结构体和枚举

struct Point {
    x: i32,
    y: i32,
}

fn main() {
    let p = Point { x: 0, y: 7 };
    
    match p {
        Point { x: 0, y } => println!("在 y 轴上,y = {}", y),
        Point { x, y: 0 } => println!("在 x 轴上,x = {}", x),
        Point { x, y } => println!("在 ({}, {})", x, y),
    }
    
    // 解构时重命名
    match p {
        Point { x: a, y: b } => println!("({}, {})", a, b),
    }
    
    // 忽略某些字段
    match p {
        Point { x, .. } => println!("x = {}", x),
    }
}

匹配守卫

fn main() {
    let num = Some(4);
    
    match num {
        Some(x) if x < 5 => println!("小于 5: {}", x),
        Some(x) => println!("大于等于 5: {}", x),
        None => println!("没有值"),
    }
}

绑定变量@

fn main() {
    let age = 25;
    
    match age {
        n @ 0..=12 => println!("儿童: {}", n),
        n @ 13..=19 => println!("青少年: {}", n),
        n @ 20..=30 => println!("青年: {}", n),
        n => println!("其他年龄: {}", n),
    }
}

Option 和 Result - 没有 Null 的世界

Option:可能没有值

fn main() {
    let some = Some(5);
    let none: Option<i32> = None;
    
    // 方法 1:match
    let value = match some {
        Some(v) => v,
        None => 0,
    };
    
    // 方法 2:unwrap_or
    let value = some.unwrap_or(0);
    
    // 方法 3:unwrap(会 panic)
    // let value = some.unwrap();  // 如果是 None 会 panic
    
    // 方法 4:expect(自定义 panic 消息)
    // let value = some.expect("应该有值");
    
    // 方法 5:map
    let doubled = some.map(|x| x * 2);  // Some(10)
    
    // 方法 6:and_then
    let result = some.and_then(|x| {
        if x > 3 {
            Some(x * 2)
        } else {
            None
        }
    });
}

Result:可能出错

enum Result<T, E> {
    Ok(T),
    Err(E),
}

use std::fs::File;
use std::io::ErrorKind;

fn main() {
    let f = File::open("hello.txt");
    
    let f = match f {
        Ok(file) => file,
        Err(error) => match error.kind() {
            ErrorKind::NotFound => match File::create("hello.txt") {
                Ok(fc) => fc,
                Err(e) => panic!("创建文件失败: {:?}", e),
            },
            other_error => panic!("打开文件失败: {:?}", other_error),
        },
    };
}

unwrap 和 expect

use std::fs::File;

fn main() {
    // unwrap:成功返回值,失败 panic
    let f = File::open("hello.txt").unwrap();
    
    // expect:可以自定义错误消息
    let f = File::open("hello.txt").expect("无法打开文件");
}

? 运算符

use std::fs::File;
use std::io;
use std::io::Read;

// ? 会自动处理错误,把 Err 返回给调用者
fn read_username_from_file() -> Result<String, io::Error> {
    let mut f = File::open("hello.txt")?;  // 如果失败,返回 Err
    let mut s = String::new();
    f.read_to_string(&mut s)?;  // 如果失败,返回 Err
    Ok(s)
}

// 更简洁的写法
fn read_username_from_file2() -> Result<String, io::Error> {
    let mut s = String::new();
    File::open("hello.txt")?.read_to_string(&mut s)?;
    Ok(s)
}

// 最简洁:使用标准库函数
fn read_username_from_file3() -> Result<String, io::Error> {
    std::fs::read_to_string("hello.txt")
}

? 也可以用于 Option

fn add_last(stack: &Vec<i32>) -> Option<i32> {
    let last = stack.last()?;  // 如果是 None,返回 None
    let second_last = stack.get(stack.len() - 2)?;  // 同上
    Some(last + second_last)
}

错误处理

不可恢复错误:panic!

fn main() {
    // panic!("崩溃了!");
    
    // 数组越界也会 panic
    let v = vec![1, 2, 3];
    // v[99];  // panic!
}

可恢复错误:Result

use std::fs::File;
use std::io::ErrorKind;

fn main() {
    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!("创建文件失败: {:?}", e),
            },
            other_error => {
                panic!("打开文件失败: {:?}", other_error);
            }
        },
    };
}

使用闭包简化

use std::fs::File;
use std::io::ErrorKind;

fn main() {
    let greeting_file = File::open("hello.txt").unwrap_or_else(|error| {
        if error.kind() == ErrorKind::NotFound {
            File::create("hello.txt").unwrap_or_else(|error| {
                panic!("创建文件失败: {:?}", error);
            })
        } else {
            panic!("打开文件失败: {:?}", error);
        }
    });
}

泛型

泛型函数

// 泛型函数:可以处理多种类型
fn largest<T: PartialOrd>(list: &[T]) -> &T {
    let mut largest = &list[0];
    
    for item in list {
        if item > largest {
            largest = item;
        }
    }
    
    largest
}

fn main() {
    let numbers = vec![34, 50, 12, 100, 65];
    let result = largest(&numbers);
    println!("最大的数字: {}", result);
    
    let chars = vec!['y', 'm', 'a', 'q'];
    let result = largest(&chars);
    println!("最大的字符: {}", result);
}

泛型结构体

// 泛型结构体
struct Point<T> {
    x: T,
    y: T,
}

// 多个泛型参数
struct Point2<T, U> {
    x: T,
    y: U,
}

fn main() {
    let integer = Point { x: 5, y: 10 };
    let float = Point { x: 1.0, y: 4.0 };
    // let mixed = Point { x: 5, y: 4.0 };  // 错误!T 必须是同一类型
    
    let mixed = Point2 { x: 5, y: 4.0 };  // 正确!
}

泛型方法

struct Point<T> {
    x: T,
    y: T,
}

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()
    }
}

fn main() {
    let p = Point { x: 5, y: 10 };
    println!("x = {}", p.x());
    
    let p_float = Point { x: 3.0, y: 4.0 };
    println!("距离原点: {}", p_float.distance_from_origin());
}

泛型枚举

// 标准库中的 Option 和 Result 就是泛型枚举
enum Option<T> {
    Some(T),
    None,
}

enum Result<T, E> {
    Ok(T),
    Err(E),
}

// 自定义泛型枚举
enum Container<T> {
    Single(T),
    Pair(T, T),
    Triple(T, T, T),
}

fn main() {
    let single = Container::Single(1);
    let pair = Container::Pair(1, 2);
    let triple = Container::Triple(1, 2, 3);
}

Trait - Rust 的接口

Trait 类似其他语言的接口,但更强大。

定义和实现 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 struct Tweet {
    pub username: String,
    pub content: String,
    pub reply: bool,
    pub retweet: bool,
}

impl Summary for Tweet {
    fn summarize(&self) -> String {
        format!("{}: {}", self.username, self.content)
    }
}

fn main() {
    let article = NewsArticle {
        headline: String::from("Rust 发布新版本"),
        location: String::from("北京"),
        author: String::from("张三"),
        content: String::from("Rust 1.70 发布了..."),
    };
    
    println!("{}", article.summarize());
    
    let tweet = Tweet {
        username: String::from("rustlover"),
        content: String::from("Rust 太棒了!"),
        reply: false,
        retweet: false,
    };
    
    println!("{}", tweet.summarize());
}

默认实现

pub trait Summary {
    fn summarize(&self) -> String {
        String::from("(阅读更多...)")
    }
    
    // 默认实现可以调用其他方法
    fn summarize_author(&self) -> String;
    
    fn summarize_with_author(&self) -> String {
        format!("作者: {}。{}", self.summarize_author(), self.summarize())
    }
}

pub struct NewsArticle {
    pub headline: String,
    pub author: String,
}

impl Summary for NewsArticle {
    fn summarize_author(&self) -> String {
        self.author.clone()
    }
    // 不实现 summarize,使用默认实现
}

fn main() {
    let article = NewsArticle {
        headline: String::from("新闻标题"),
        author: String::from("张三"),
    };
    
    println!("{}", article.summarize());           // 默认实现
    println!("{}", article.summarize_with_author()); // 调用默认方法
}

Trait 作为参数

pub trait Summary {
    fn summarize(&self) -> String;
}

// 方式 1:impl Trait 语法
pub fn notify(item: &impl Summary) {
    println!("突发新闻!{}", item.summarize());
}

// 方式 2:Trait Bound 语法(更灵活)
pub fn notify2<T: Summary>(item: &T) {
    println!("突发新闻!{}", item.summarize());
}

// 多个 Trait
pub fn notify3(item: &(impl Summary + std::fmt::Display)) {
    println!("{}", item);
}

// 使用 where 子句(更清晰)
pub fn some_function<T, U>(t: &T, u: &U) -> i32
where
    T: std::fmt::Display + Clone,
    U: std::fmt::Debug + Clone,
{
    // 函数体
    0
}

返回 Trait

pub trait Summary {
    fn summarize(&self) -> String;
}

pub struct NewsArticle {
    pub headline: String,
}

impl Summary for NewsArticle {
    fn summarize(&self) -> String {
        self.headline.clone()
    }
}

// 返回实现了 Trait 的类型
fn returns_summarizable() -> impl Summary {
    NewsArticle {
        headline: String::from("新闻标题"),
    }
}

// 注意:不能返回不同类型!
// fn returns_summarizable(switch: bool) -> impl Summary {
//     if switch {
//         NewsArticle { headline: String::from("新闻") }
//     } else {
//         Tweet { username: String::from("user"), content: String::from("内容") }
//     }
// }
// 这会编译错误!

Trait Bound 条件

use std::fmt::Display;

// 只有实现了 PartialOrd 和 Copy 的类型才能用这个函数
fn largest<T: PartialOrd + Copy>(list: &[T]) -> T {
    let mut largest = list[0];
    
    for &item in list {
        if item > largest {
            largest = item;
        }
    }
    
    largest
}

// 使用 where 让代码更清晰
fn some_function<T, U>(t: &T, u: &U) -> i32
where
    T: Display + Clone,
    U: Clone + std::fmt::Debug,
{
    0
}

常见 Trait

// Debug:打印调试信息
#[derive(Debug)]
struct Point {
    x: i32,
    y: i32,
}

// Clone:深拷贝
#[derive(Clone)]
struct Data {
    value: i32,
}

// Copy:栈上复制(隐式)
#[derive(Copy, Clone)]
struct Size {
    width: u32,
    height: u32,
}

// PartialEq:相等比较
#[derive(PartialEq)]
struct Person {
    name: String,
    age: u32,
}

fn main() {
    let p1 = Point { x: 1, y: 2 };
    println!("{:?}", p1);  // Debug
    
    let d1 = Data { value: 10 };
    let d2 = d1.clone();  // Clone
    
    let s1 = Size { width: 10, height: 20 };
    let s2 = s1;  // Copy(不需要 clone)
    
    let p1 = Person { name: String::from("张三"), age: 25 };
    let p2 = Person { name: String::from("张三"), age: 25 };
    println!("{}", p1 == p2);  // true
}

生命周期

生命周期是 Rust 最难的概念之一。它确保引用始终有效。

为什么需要生命周期?

// 这个函数会报错!
fn longest(x: &str, y: &str) -> &str {
    if x.len() > y.len() {
        x
    } else {
        y
    }
}
// 编译器不知道返回的引用是 x 还是 y
// 所以不知道返回值的生命周期

生命周期标注

// 告诉编译器:返回值的生命周期与参数相同
fn longest<'a>(x: &'a str, y: &'a str) -> &'a str {
    if x.len() > y.len() {
        x
    } else {
        y
    }
}

fn main() {
    let string1 = String::from("long string");
    let string2 = String::from("xyz");
    
    let result = longest(&string1, &string2);
    println!("最长的字符串: {}", result);
    
    // 这个例子会报错
    let string3 = String::from("long string");
    let result;
    {
        let string4 = String::from("xyz");
        result = longest(&string3, &string4);  // string4 活得不够长
    }
    // println!("{}", result);  // 错误!string4 已经被释放
}

生命周期标注语法

// 生命周期参数以 ' 开头,通常用 'a
fn function<'a>(x: &'a str) -> &'a str {
    x
}

// 多个生命周期参数
fn function2<'a, 'b>(x: &'a str, y: &'b str) -> &'a str {
    x  // 返回 x,所以生命周期是 'a
}

// 结构体中的生命周期
struct ImportantExcerpt<'a> {
    part: &'a str,  // 引用必须比结构体活得长
}

fn main() {
    let novel = String::from("Call me Ishmael. Some years ago...");
    let first_sentence = novel.split('.').next().unwrap();
    
    let excerpt = ImportantExcerpt {
        part: first_sentence,
    };
    
    // excerpt 离开作用域后,novel 仍然有效
}

生命周期省略

有些情况下,编译器可以自动推断生命周期:

// 省略前
fn first_word<'a>(s: &'a str) -> &'a str {
    let bytes = s.as_bytes();
    
    for (i, &item) in bytes.iter().enumerate() {
        if item == b' ' {
            return &s[0..i];
        }
    }
    
    &s[..]
}

// 省略后(编译器自动推断)
fn first_word(s: &str) -> &str {
    let bytes = s.as_bytes();
    
    for (i, &item) in bytes.iter().enumerate() {
        if item == b' ' {
            return &s[0..i];
        }
    }
    
    &s[..]
}

静态生命周期

// 'static:整个程序运行期间都有效
let s: &'static str = "这是一个静态字符串";
// 字符串字面量都是 'static 的

// 但不要滥用 'static 来解决生命周期问题

方法的生命周期

struct ImportantExcerpt<'a> {
    part: &'a str,
}

impl<'a> ImportantExcerpt<'a> {
    fn level(&self) -> i32 {
        3
    }
    
    fn announce_and_return_part(&self, announcement: &str) -> &str {
        println!("请注意: {}", announcement);
        self.part
    }
}

闭包

闭包是可以捕获环境的匿名函数。

基本语法

fn main() {
    // 基本闭包
    let add = |a, b| a + b;
    println!("1 + 2 = {}", add(1, 2));
    
    // 带类型标注
    let add_explicit = |a: i32, b: i32| -> i32 {
        a + b
    };
    
    // 多行闭包
    let calculate = |a, b| {
        let sum = a + b;
        let product = a * b;
        (sum, product)
    };
    
    let (s, p) = calculate(3, 4);
    println!("和: {}, 积: {}", s, p);
}

捕获环境

fn main() {
    let x = 4;
    
    // 闭包可以捕获外部变量
    let equal_to_x = |z| z == x;
    
    let y = 4;
    assert!(equal_to_x(y));
    
    // 函数不能这样做!
    // fn equal_to_x(z: i32) -> bool {
    //     z == x  // 错误!函数不能捕获环境
    // }
}

闭包的三种捕获方式

fn main() {
    // 1. FnOnce:获取所有权(只能调用一次)
    let name = String::from("张三");
    let consume = move || {
        println!("再见,{}!", name);  // name 被移动到闭包中
    };
    consume();
    // println!("{}", name);  // 错误!name 已经被移动
    
    // 2. FnMut:可变借用
    let mut list = vec![1, 2, 3];
    let mut push_to_list = || {
        list.push(4);  // 可变借用
    };
    push_to_list();
    println!("{:?}", list);
    
    // 3. Fn:不可变借用
    let list = vec![1, 2, 3];
    let print_list = || {
        println!("{:?}", list);  // 不可变借用
    };
    print_list();
    println!("{:?}", list);  // list 仍然可用
}

闭包作为参数

fn main() {
    let list = vec![1, 2, 3, 4, 5];
    
    // 使用闭包
    let result: Vec<i32> = list.iter().map(|x| x * 2).collect();
    println!("{:?}", result);
    
    // 使用函数
    fn double(x: &i32) -> i32 {
        *x * 2
    }
    let result2: Vec<i32> = list.iter().map(double).collect();
    println!("{:?}", result2);
}

迭代器适配器

fn main() {
    let numbers = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
    
    // map:转换
    let doubled: Vec<i32> = numbers.iter().map(|x| x * 2).collect();
    println!("翻倍: {:?}", doubled);
    
    // filter:过滤
    let evens: Vec<&i32> = numbers.iter().filter(|x| *x % 2 == 0).collect();
    println!("偶数: {:?}", evens);
    
    // fold:累积
    let sum: i32 = numbers.iter().fold(0, |acc, x| acc + x);
    println!("总和: {}", sum);
    
    // 链式调用
    let result: Vec<i32> = numbers
        .iter()
        .filter(|x| *x % 2 == 0)  // 过滤偶数
        .map(|x| x * 2)            // 翻倍
        .take(3)                   // 取前 3 个
        .collect();
    println!("结果: {:?}", result);
}

迭代器

创建迭代器

fn main() {
    let v = vec![1, 2, 3];
    
    // iter():不可变引用
    let iter1 = v.iter();
    
    // iter_mut():可变引用
    let mut v2 = vec![1, 2, 3];
    let iter2 = v2.iter_mut();
    
    // into_iter():获取所有权
    let iter3 = v.into_iter();
}

Iterator trait

pub trait Iterator {
    type Item;
    
    fn next(&mut self) -> Option<Self::Item>;
    
    // 其他方法都有默认实现
}

fn main() {
    let v = vec![1, 2, 3];
    
    let mut iter = v.iter();
    
    assert_eq!(iter.next(), Some(&1));
    assert_eq!(iter.next(), Some(&2));
    assert_eq!(iter.next(), Some(&3));
    assert_eq!(iter.next(), None);
}

消费适配器

fn main() {
    let v = vec![1, 2, 3, 4, 5];
    
    // sum:求和
    let sum: i32 = v.iter().sum();
    println!("总和: {}", sum);
    
    // count:计数
    let count = v.iter().count();
    println!("数量: {}", count);
    
    // any:是否有任意元素满足条件
    let has_even = v.iter().any(|x| x % 2 == 0);
    println!("有偶数: {}", has_even);
    
    // all:是否所有元素都满足条件
    let all_positive = v.iter().all(|x| *x > 0);
    println!("都是正数: {}", all_positive);
    
    // find:查找第一个满足条件的元素
    let first_even = v.iter().find(|x| *x % 2 == 0);
    println!("第一个偶数: {:?}", first_even);
    
    // position:查找位置
    let pos = v.iter().position(|x| *x == 3);
    println!("3 的位置: {:?}", pos);
}

自定义迭代器

struct Counter {
    count: usize,
    max: usize,
}

impl Counter {
    fn new(max: usize) -> Counter {
        Counter { count: 0, max }
    }
}

impl Iterator for Counter {
    type Item = usize;
    
    fn next(&mut self) -> Option<Self::Item> {
        if self.count < self.max {
            self.count += 1;
            Some(self.count)
        } else {
            None
        }
    }
}

fn main() {
    let counter = Counter::new(5);
    
    let sum: usize = counter.sum();
    println!("总和: {}", sum);  // 15
    
    let counter2 = Counter::new(5);
    let doubled: Vec<usize> = counter2.map(|x| x * 2).collect();
    println!("翻倍: {:?}", doubled);  // [2, 4, 6, 8, 10]
}

模块系统

模块基础

// src/lib.rs 或 src/main.rs

mod front_of_house {
    pub mod hosting {
        pub fn add_to_waitlist() {
            println!("添加到等待列表");
        }
        
        fn seat_at_table() {
            println!("安排就座");
        }
    }
    
    mod serving {
        fn take_order() {
            println!("点餐");
        }
        
        fn serve_order() {
            println!("上菜");
        }
    }
}

pub fn eat_at_restaurant() {
    // 绝对路径
    crate::front_of_house::hosting::add_to_waitlist();
    
    // 相对路径
    front_of_house::hosting::add_to_waitlist();
}

use 关键字

mod front_of_house {
    pub mod hosting {
        pub fn add_to_waitlist() {}
    }
}

// 引入模块
use crate::front_of_house::hosting;

// 引入函数
use crate::front_of_house::hosting::add_to_waitlist;

// 引入多个项目
use std::collections::{HashMap, HashSet};

// 引入所有公共项目
use std::collections::*;

// 重命名
use std::fmt::Result as FmtResult;

fn main() {
    hosting::add_to_waitlist();
    add_to_waitlist();
}

文件分离

// src/lib.rs
mod front_of_house;  // 声明模块

pub use crate::front_of_house::hosting;

pub fn eat_at_restaurant() {
    hosting::add_to_waitlist();
}

// src/front_of_house.rs(或 src/front_of_house/mod.rs)
pub mod hosting;

// src/front_of_house/hosting.rs(或 src/front_of_house/hosting/mod.rs)
pub fn add_to_waitlist() {}

访问权限

mod outer {
    pub fn public_function() {
        println!("公开函数");
    }
    
    fn private_function() {
        println!("私有函数");
    }
    
    pub mod inner {
        pub fn inner_public() {
            println!("内部公开函数");
        }
        
        fn inner_private() {
            println!("内部私有函数");
        }
    }
}

fn main() {
    outer::public_function();
    // outer::private_function();  // 错误!私有
    outer::inner::inner_public();
    // outer::inner::inner_private();  // 错误!私有
}

常用集合

Vec 向量

fn main() {
    // 创建
    let mut v: Vec<i32> = Vec::new();
    let v2 = vec![1, 2, 3, 4, 5];
    
    // 添加元素
    v.push(1);
    v.push(2);
    v.push(3);
    
    // 读取元素
    let third = &v[2];  // 可能 panic
    let third = v.get(2);  // 返回 Option<&T>
    
    // 遍历
    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")),
        SpreadsheetCell::Float(10.12),
    ];
}

String 字符串

fn main() {
    // 创建
    let mut s = String::new();
    let s2 = "initial contents".to_string();
    let s3 = String::from("initial contents");
    
    // 追加
    s.push_str("hello");
    s.push('!');  // 单个字符
    
    // 拼接
    let s1 = String::from("Hello, ");
    let s2 = String::from("world!");
    let s3 = s1 + &s2;  // s1 被移动,s2 被借用
    
    // format! 宏
    let s1 = String::from("tic");
    let s2 = String::from("tac");
    let s3 = String::from("toe");
    let s = format!("{}-{}-{}", s1, s2, s3);
    
    // 索引(不支持!)
    // let c = s[0];  // 错误!
    
    // 切片(小心 UTF-8)
    let hello = "你好";
    // let s = &hello[0..1];  // 可能 panic!中文是多字节
    let s = &hello[0..3];  // 正确,一个中文字符占 3 字节
    
    // 遍历
    for c in "你好".chars() {
        println!("{}", c);  // 你,好
    }
    
    for b in "你好".bytes() {
        println!("{}", b);  // 每个字节
    }
}

HashMap<K, V> 哈希表

use std::collections::HashMap;

fn main() {
    // 创建
    let mut scores = HashMap::new();
    
    // 插入
    scores.insert(String::from("Blue"), 10);
    scores.insert(String::from("Red"), 50);
    
    // 访问
    let team_name = String::from("Blue");
    let score = scores.get(&team_name);  // Option<&V>
    
    // 遍历
    for (key, value) in &scores {
        println!("{}: {}", key, value);
    }
    
    // 更新
    scores.insert(String::from("Blue"), 25);  // 覆盖
    
    // 只在键不存在时插入
    scores.entry(String::from("Yellow")).or_insert(50);
    scores.entry(String::from("Blue")).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;
    }
    
    println!("{:?}", map);
}

智能指针

Box 堆分配

fn main() {
    // 在堆上分配
    let b = Box::new(5);
    println!("b = {}", b);
    
    // 递归类型
    enum List {
        Cons(i32, Box<List>),
        Nil,
    }
    
    use List::{Cons, Nil};
    
    let list = Cons(1, Box::new(Cons(2, Box::new(Cons(3, Box::new(Nil))))));
}

Rc 引用计数

use std::rc::Rc;

fn main() {
    // 多所有权
    let a = Rc::new(5);
    let b = Rc::clone(&a);  // 增加引用计数
    let c = Rc::clone(&a);  // 再增加
    
    println!("引用计数: {}", Rc::strong_count(&a));  // 3
    
    // 当所有引用离开作用域,数据才会被释放
}

RefCell 内部可变性

use std::cell::RefCell;

fn main() {
    // 在运行时检查借用规则,而不是编译时
    let x = RefCell::new(5);
    
    // 可变借用
    *x.borrow_mut() += 1;
    
    // 不可变借用
    println!("x = {}", *x.borrow());
    
    // 注意:运行时违反规则会 panic
    // let ref1 = x.borrow();
    // let ref2 = x.borrow_mut();  // panic!同时有可变和不可变借用
}

组合使用

use std::cell::RefCell;
use std::rc::Rc;

#[derive(Debug)]
struct Node {
    value: i32,
    children: RefCell<Vec<Rc<Node>>>,
}

fn main() {
    let leaf = Rc::new(Node {
        value: 3,
        children: RefCell::new(vec![]),
    });
    
    let branch = Rc::new(Node {
        value: 5,
        children: RefCell::new(vec![Rc::clone(&leaf)]),
    });
    
    println!("branch: {:?}", branch);
}

并发编程

线程

use std::thread;
use std::time::Duration;

fn main() {
    // 创建线程
    let handle = thread::spawn(|| {
        for i in 1..10 {
            println!("子线程: {}", i);
            thread::sleep(Duration::from_millis(1));
        }
    });
    
    for i in 1..5 {
        println!("主线程: {}", i);
        thread::sleep(Duration::from_millis(1));
    }
    
    // 等待线程结束
    handle.join().unwrap();
}

move 闭包

use std::thread;

fn main() {
    let v = vec![1, 2, 3];
    
    // move 把所有权转移到线程中
    let handle = thread::spawn(move || {
        println!("向量: {:?}", v);
    });
    
    // println!("{:?}", v);  // 错误!v 已经被移动
    
    handle.join().unwrap();
}

消息传递

use std::sync::mpsc;
use std::thread;

fn main() {
    // 创建通道
    let (tx, rx) = mpsc::channel();
    
    thread::spawn(move || {
        let val = String::from("你好");
        tx.send(val).unwrap();
        // println!("{}", val);  // 错误!val 已经被移动
    });
    
    // 接收消息(阻塞)
    let received = rx.recv().unwrap();
    println!("收到: {}", received);
    
    // 多个发送者
    let (tx, rx) = mpsc::channel();
    let tx1 = tx.clone();
    
    thread::spawn(move || {
        let vals = vec![
            String::from("你好"),
            String::from("来自"),
            String::from("线程"),
        ];
        
        for val in vals {
            tx1.send(val).unwrap();
        }
    });
    
    thread::spawn(move || {
        let vals = vec![
            String::from("更多"),
            String::from("消息"),
        ];
        
        for val in vals {
            tx.send(val).unwrap();
        }
    });
    
    // 迭代接收
    for received in rx {
        println!("收到: {}", received);
    }
}

共享状态

use std::sync::{Arc, Mutex};
use std::thread;

fn main() {
    // Mutex:互斥锁
    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!("结果: {}", *counter.lock().unwrap());
}

常见陷阱与技巧

1. 所有权陷阱

fn main() {
    let v = vec![1, 2, 3];
    let v2 = v;  // 移动
    // println!("{:?}", v);  // 错误!v 已经无效
    
    // 解决方案 1:克隆
    let v3 = vec![1, 2, 3];
    let v4 = v3.clone();
    println!("{:?} {:?}", v3, v4);  // 都有效
    
    // 解决方案 2:引用
    let v5 = vec![1, 2, 3];
    let v6 = &v5;
    println!("{:?} {:?}", v5, v6);  // 都有效
}

2. 借用检查器陷阱

fn main() {
    let mut v = vec![1, 2, 3];
    
    // 错误示例
    // let first = &v[0];  // 不可变借用
    // v.push(4);          // 可变借用
    // println!("{}", first);  // 错误!同时有可变和不可变借用
    
    // 正确做法
    let first = v[0];
    v.push(4);
    println!("{}", first);
}

3. 生命周期陷阱

// 错误示例
// fn longest(x: &str, y: &str) -> &str {
//     let result = String::from("really long string");
//     result.as_str()  // 错误!result 在函数结束时被释放
// }

// 正确做法
fn longest<'a>(x: &'a str, y: &'a str) -> &'a str {
    if x.len() > y.len() {
        x
    } else {
        y
    }
}

4. 字符串陷阱

fn main() {
    let s = "你好世界";
    
    // 错误:中文字符占 3 字节
    // let c = &s[0..1];  // panic!
    
    // 正确做法
    let c = &s[0..3];  // "你"
    println!("{}", c);
    
    // 更好的做法:使用 chars()
    for c in s.chars() {
        println!("{}", c);
    }
}

5. 整数溢出

fn main() {
    // debug 模式会 panic,release 模式会回绕
    let mut x: u8 = 255;
    // x += 1;  // debug: panic, release: 0
    
    // 显式处理
    x = x.checked_add(1).unwrap_or(0);  // 溢出返回 None
    x = x.saturating_add(1);  // 溢出保持最大值
    x = x.wrapping_add(1);  // 溢出回绕
}

6. 使用 Option 和 Result

fn main() {
    // 不要用 unwrap(),用 ? 或 match
    // let x = some_option.unwrap();  // 可能 panic
    
    // 更好的做法
    let x = match some_option {
        Some(v) => v,
        None => return,
    };
    
    // 或者
    let x = some_option.ok_or("错误")?;
}

7. 避免克隆

fn main() {
    // 不要过度使用克隆
    let s1 = String::from("hello");
    let s2 = s1.clone();  // 有时是必要的,但考虑是否可以用引用
    
    // 使用引用
    fn print_string(s: &str) {
        println!("{}", s);
    }
    
    print_string(&s1);  // 不需要克隆
}

8. 使用迭代器代替循环

fn main() {
    let numbers = vec![1, 2, 3, 4, 5];
    
    // 不推荐
    let mut sum = 0;
    for n in &numbers {
        sum += n;
    }
    
    // 推荐
    let sum: i32 = numbers.iter().sum();
    
    // 链式操作
    let result: Vec<i32> = numbers
        .iter()
        .filter(|x| *x % 2 == 0)
        .map(|x| x * 2)
        .collect();
}

9. 使用 ? 传播错误

use std::fs::File;
use std::io::Read;

// 不推荐
fn read_file() -> Result<String, std::io::Error> {
    let f = File::open("data.txt");
    let mut f = match f {
        Ok(file) => file,
        Err(e) => return Err(e),
    };
    
    let mut s = String::new();
    match f.read_to_string(&mut s) {
        Ok(_) => Ok(s),
        Err(e) => Err(e),
    }
}

// 推荐
fn read_file_better() -> Result<String, std::io::Error> {
    let mut s = String::new();
    File::open("data.txt")?.read_to_string(&mut s)?;
    Ok(s)
}

// 最推荐
fn read_file_best() -> Result<String, std::io::Error> {
    std::fs::read_to_string("data.txt")
}

10. 使用 derive 减少样板代码

// 使用 derive 自动实现常用 trait
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
struct Person {
    name: String,
    age: u32,
}

fn main() {
    let p1 = Person {
        name: String::from("张三"),
        age: 25,
    };
    
    let p2 = p1.clone();
    
    println!("{:?}", p1);  // Debug
    println!("{}", p1 == p2);  // PartialEq
}

总结

Rust 的核心概念:

  1. 所有权 - 每个值有且只有一个所有者,离开作用域自动释放
  2. 借用 - 通过引用临时访问值,不获取所有权
  3. 生命周期 - 确保引用始终有效,防止悬垂指针

学习路线建议

入门阶段(1-2周)
├── 基本语法(变量、函数、控制流)
├── 所有权系统(重点!)
├── 引用与借用
└── 结构体和枚举

进阶阶段(2-4周)
├── 模式匹配
├── 错误处理(OptionResult)
├── 泛型和 Trait
├── 生命周期标注
└── 闭包和迭代器

实战阶段(持续)
├── 模块系统
├── 常用集合(Vec、HashMap)
├── 智能指针
├── 并发编程
└── 异步编程(async/await

推荐资源

  1. 官方书籍:《The Rust Programming Language》(Rust 程序设计语言)
  2. 练习网站:Rustlings(github.com/rust-lang/r…
  3. 实战项目:Rust by Example(doc.rust-lang.org/rust-by-exa…
  4. 社区:Rust 中文社区、RustCC

常见编译错误速查

错误信息原因解决方法
borrow of moved value值被移动后使用使用引用 &.clone()
cannot borrow as mutable不可变变量借为可变mut 或重新设计
cannot borrow as mutable more than once同时有多个可变引用缩小引用作用域
lifetime may not live long enough生命周期不明确添加生命周期标注
use of possibly uninitialized variable变量可能未初始化确保所有路径都初始化

最后的话:Rust 确实有学习曲线,但一旦你理解了所有权系统,你会发现它其实很符合直觉。编译器虽然严格,但它是在帮你避免运行时错误。坚持写下去,你会发现 Rust 的魅力!

祝你学习愉快!🦀