← 返回首页← 专题总览

Rust 从零学习指南

> 对应官方文档 Chapter 1: Getting Started
前端架构师通关手册 · 专题 18
本指南基于 [The Rust Programming Language](https://doc.rust-lang.org/stable/book/)(官方圣经)的结构编写,
每个知识点都配有详细讲解和可运行的 Demo 示例。
> 适用版本:Rust 1.97.0+,Edition 2024

第一部分:环境搭建与 Hello Cargo

对应官方文档 Chapter 1: Getting Started

1.1 安装 Rust

使用 rustup 安装(推荐)

rustup 是 Rust 的官方工具链管理器,用于安装、更新和管理 Rust 版本。

Windows 安装

  1. 下
载安装器:https://www.rust-lang.org/tools/install
  1. 运
行 rustup-init.exe,按提示安装
  1. 安
装过程中会自动安装 Microsoft C++ Build Tools(如未安装)

macOS / Linux 安装

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

验证安装

rustc --version    # 查看 Rust 编译器版本
cargo --version    # 查看 Cargo 包管理器版本
rustup --version   # 查看 rustup 版本

Rust 工具链说明

工具用途说明
rustcRust 编译器将 .rs 文件编译为可执行文件或库
cargo包管理器 + 构建系统管理依赖、编译、测试、发布
rustup工具链管理器安装/切换 Rust 版本、管理目标平台
rustfmt代码格式化统一代码风格
clippy代码检查工具发现常见错误和改进建议
rustdoc文档生成器从注释生成 HTML 文档

更新与卸载

rustup update          # 更新 Rust 到最新版本
rustup self uninstall  # 卸载 Rust

1.2 Hello World

直接编译运行

// main.rs
fn main() {
    println!("Hello, world!");
}
rustc main.rs    # 编译生成可执行文件
./main           # 运行(Windows 上是 main.exe)

关于 fn main()


1.3 Hello Cargo

什么是 Cargo?

Cargo 是 Rust 的构建系统和包管理器。它可以:

创建新项目

# 创建二进制项目(可执行文件)
cargo new hello_cargo
cd hello_cargo

# 创建库项目
cargo new --lib my_library

项目结构

hello_cargo/
├── Cargo.toml      # 项目配置文件(类似 package.json / build.gradle)
├── .gitignore      # Git 忽略文件(自动生成)
└── src/
    └── main.rs     # 入口文件

Cargo.toml 文件解析

[package]
name = "hello_cargo"        # 项目名称
version = "0.1.0"           # 版本号(语义化版本)
edition = "2024"            # Rust 版本(2015/2018/2021/2024)
authors = ["Your Name <you@example.com>"]
description = "A sample project"
license = "MIT"

[dependencies]              # 依赖项(第三方 crate)
Edition 说明:

构建与运行

# 编译并运行(Debug 模式,编译快,运行慢)
cargo run

# 仅编译(不运行)
cargo build

# 发布编译(Release 模式,编译慢,运行快,有优化)
cargo build --release

# 快速检查编译错误(不生成可执行文件,比 build 更快)
cargo check

# 格式化代码
cargo fmt

# 运行 clippy 检查
cargo clippy

Cargo 常用命令速查

命令说明
cargo new <name>创建新项目
cargo new --lib <name>创建库项目
cargo buildDebug 模式编译
cargo build --releaseRelease 模式编译
cargo run编译并运行
cargo check仅检查编译错误
cargo test运行测试
cargo doc --open生成并打开文档
cargo add <crate>添加依赖
cargo update更新依赖
cargo clean清理构建产物
cargo fmt格式化代码
cargo clippy代码检查

Demo 1.1:创建并运行第一个项目

# 步骤 1:创建项目
cargo new demo_hello
cd demo_hello

# 步骤 2:查看生成的代码
cat src/main.rs
# 输出:
# fn main() {
#     println!("Hello, world!");
# }

# 步骤 3:运行
cargo run
# 输出:Hello, world!

# 步骤 4:修改代码
echo 'fn main() { println!("你好,Rust!"); }' > src/main.rs

# 步骤 5:重新运行
cargo run
# 输出:你好,Rust!

第二部分:基础编程概念

对应官方文档 Chapter 3: Common Programming Concepts

2.1 变量与可变性

不可变变量(默认)

fn main() {
    let x = 5;
    println!("x 的值是: {}", x);
    // x = 6;  // ❌ 编译错误!x 是不可变的
    // error[E0384]: cannot assign twice to immutable variable `x`
}
为什么默认不可变?

可变变量

fn main() {
    let mut x = 5;
    println!("x 的值是: {}", x);  // 5
    x = 6;  // ✅ 正确!x 是可变的
    println!("x 的值是: {}", x);  // 6
}

变量遮蔽(Shadowing)

fn main() {
    let x = 5;
    
    // 遮蔽:用同名新变量覆盖旧变量
    // 注意:这不是修改原变量,而是创建了一个新变量
    let x = x + 1;  // 这里是 i32,值为 6
    
    {
        // 内部作用域遮蔽
        let x = x * 2;  // 值为 12
        println!("内部 x: {}", x);  // 12
    }
    // 内部作用域结束,遮蔽消失
    
    println!("外部 x: {}", x);  // 6
    
    // 遮蔽可以改变类型 —— 这是 mut 做不到的
    let spaces = "   ";        // &str 类型
    let spaces = spaces.len(); // usize 类型
    // 如果写成 let mut spaces = "..."; spaces = spaces.len(); 会报错!
}

遮蔽 vs mut 的区别

特性mut遮蔽(Shadowing)
改变值✅✅
改变类型❌✅
创建新变量❌✅
内存地址不变改变
作用域整个作用域从遮蔽点到作用域结束

常量(Constants)

// 常量:必须标注类型,必须能在编译时求值
const THREE_HOURS_IN_SECONDS: u32 = 60 * 60 * 3;
const MAX_POINTS: u32 = 100_000;  // 数字可以用 _ 分隔提高可读性

fn main() {
    println!("最大点数: {}", MAX_POINTS);
    println!("三小时秒数: {}", THREE_HOURS_IN_SECONDS);
}
常量 vs 不可变变量的区别:
特性不可变变量 let常量 const
类型标注可选(推断)必须
遮蔽可以不可以
作用域块级作用域全局/块级
值运行时计算编译时常量
内存有内存地址内联到使用处

Demo 2.1:变量遮蔽的实际应用

fn main() {
    // 场景:用户输入字符串,需要转换为数字
    let input = "42";           // 用户输入(字符串)
    println!("输入: {}", input);
    
    let input = input.trim();   // 去除空白(遮蔽,仍是 &str)
    println!("去除空白: {}", input);
    
    let input: u32 = input.parse()  // 解析为数字(遮蔽,改变类型)
        .expect("请输入有效数字");
    println!("解析后: {}", input);
    
    let input = input * 2;      // 计算(遮蔽)
    println!("翻倍: {}", input);
}

2.2 数据类型

Rust 是静态类型语言,所有变量在编译时必须已知类型。但 Rust 支持类型推断,大多数情况下不需要显式标注。

标量类型(Scalar Types)

标量类型代表单个值。Rust 有四种标量类型:整数、浮点数、布尔值和字符。

整数类型

长度有符号无符号范围
8位i8u8i8: -128~127, u8: 0~255
16位i16u16i16: -32768~32767
32位i32u32i32: 约 ±21亿
64位i64u64i64: 约 ±922京
128位i128u128极大范围
架构isizeusize32位系统32位,64位系统64位
fn main() {
    let x = 42;           // 默认 i32
    let x: i64 = 42;      // 显式类型标注
    let x = 42i64;        // 类型后缀
    let x = 0xff;         // 十六进制
    let x = 0o77;         // 八进制
    let x = 0b1111_0000;  // 二进制
    let x = b'A';         // 字节 (u8),值为 65
    
    // 整数字面量中的 _ 只是可读性分隔符,不影响值
    let x = 1_000_000;    // 等于 1000000
    let x = 0xff_ff_ff_ff; // 等于 4294967295
}
整数溢出:

浮点类型

fn main() {
    let x = 2.0;     // f64(默认,精度更高)
    let y: f32 = 3.0;  // f32(单精度)
    
    // 浮点数运算
    let sum = 5.0 + 10.0;
    let difference = 95.5 - 4.3;
    let product = 4.0 * 30.0;
    let quotient = 56.7 / 32.2;
    let remainder = 55.0 % 3.0;
}

布尔类型

fn main() {
    let t = true;
    let f: bool = false;
    
    // 布尔值在条件判断中使用
    if t {
        println!("t 是 true");
    }
}

字符类型

fn main() {
    let c = 'z';
    let z = 'ℤ';
    let heart_eyed_cat = '😻';  // Rust 的 char 是 4 字节 Unicode 标量值
    
    // 注意:char 是单引号,字符串是双引号
    let a = 'a';     // char,4 字节
    let b = "a";     // &str,字符串切片
}
为什么 Rust 的 char 是 4 字节?

复合类型(Compound Types)

复合类型可以将多个值组合成一种类型。Rust 有两种原生复合类型:元组和数组。

元组(Tuple)

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

数组(Array)

fn main() {
    let a = [1, 2, 3, 4, 5];              // 固定长度
    let a: [i32; 5] = [1, 2, 3, 4, 5];    // 显式类型和长度
    let a = [3; 5];                        // [3, 3, 3, 3, 3]
    
    // 访问元素
    let first = a[0];
    let second = a[1];
    
    // 越界访问会 panic(运行时错误)
    // let invalid = a[10];  // thread 'main' panicked at 'index out of bounds'
}
数组 vs 向量(Vec): 何时使用数组:

Demo 2.2:温度转换器

fn main() {
    let celsius: f64 = 25.0;
    let fahrenheit = celsius_to_fahrenheit(celsius);
    println!("{}°C = {}°F", celsius, fahrenheit);
    
    let fahrenheit: f64 = 77.0;
    let celsius = fahrenheit_to_celsius(fahrenheit);
    println!("{}°F = {}°F", fahrenheit, celsius);
}

fn celsius_to_fahrenheit(c: f64) -> f64 {
    c * 9.0 / 5.0 + 32.0
}

fn fahrenheit_to_celsius(f: f64) -> f64 {
    (f - 32.0) * 5.0 / 9.0
}

2.3 函数

基本函数

fn main() {
    println!("Hello, world!");
    another_function(5, 10);
}

fn another_function(x: i32, y: i32) {
    println!("x = {}, y = {}", x, y);
}
函数命名规范:snake_case(小写字母 + 下划线)

语句与表达式

这是 Rust 的核心概念!
fn main() {
    // 语句(Statement):执行操作但不返回值,以 ; 结尾
    let x = 5;  // let 语句
    
    // ❌ 报错:let 语句没有返回值
    // let y = (let x = 5);
    
    // 表达式(Expression):计算并返回值,没有 ;
    let y = {
        let x = 3;
        x + 1  // 没有分号,这是返回值(表达式)
    };
    // y = 4
    
    // 代码块 {} 是表达式,返回最后一个表达式的值
    let z = {
        2 + 2  // 返回 4
    };
}
关键区别:

带返回值的函数

// 使用 -> 标注返回类型
fn five() -> i32 {
    5  // 没有分号的表达式就是返回值
}

fn plus_one(x: i32) -> i32 {
    x + 1  // 返回 x + 1
}

// ❌ 错误:加了分号变成语句,返回 (),与声明的 i32 不匹配
// fn plus_one_wrong(x: i32) -> i32 {
//     x + 1;  // 这是一个语句,返回 ()
// }

fn main() {
    let x = five();
    let y = plus_one(x);
    println!("x = {}, y = {}", x, y);  // x = 5, y = 6
}

发散函数(Diverging Functions)

// 发散函数永不返回,返回类型是 !
fn never_returns() -> ! {
    panic!("这个函数永不返回");
}

// 用途:panic!、loop + break、exit 等
fn forever() -> ! {
    loop {
        println!("永远循环...");
        std::thread::sleep(std::time::Duration::from_secs(1));
    }
}

Demo 2.3:计算斐波那契数

fn main() {
    for n in 0..10 {
        println!("fib({}) = {}", n, fibonacci(n));
    }
}

fn fibonacci(n: u32) -> u64 {
    if n == 0 {
        return 0;
    }
    if n == 1 {
        return 1;
    }
    
    let mut prev = 0u64;
    let mut curr = 1u64;
    
    for _ in 2..=n {
        let next = prev + curr;
        prev = curr;
        curr = next;
    }
    
    curr
}

2.4 控制流

if 表达式

fn main() {
    let number = 6;
    
    // if 表达式
    if number % 4 == 0 {
        println!("能被 4 整除");
    } else if number % 3 == 0 {
        println!("能被 3 整除");
    } else {
        println!("不能被 4 或 3 整除");
    }
    
    // if 作为表达式(各分支返回类型必须一致)
    let condition = true;
    let number = if condition { 5 } else { 0 };
    println!("number = {}", number);  // 5
    
    // ❌ 错误:分支返回类型不一致
    // let number = if condition { 5 } else { "six" };
}

循环

loop 无限循环

fn main() {
    let mut counter = 0;
    
    // loop 可以返回值
    let result = loop {
        counter += 1;
        if counter == 10 {
            break counter * 2;  // break 可以返回值
        }
    };
    println!("result = {}", result);  // 20
    
    // 嵌套循环与标签
    let mut count = 0;
    'outer: loop {
        println!("外层: {}", count);
        let mut remaining = 10;
        
        loop {
            println!("内层: {}", remaining);
            if remaining == 9 {
                break;  // 跳出内层循环
            }
            if count == 2 {
                break 'outer;  // 跳出外层循环
            }
            remaining -= 1;
        }
        count += 1;
    }
}

while 循环

fn main() {
    let mut number = 3;
    while number != 0 {
        println!("{}!", number);
        number -= 1;
    }
    println!("发射!");
}

for 循环

fn main() {
    // 遍历数组
    let arr = [10, 20, 30, 40, 50];
    for element in arr.iter() {
        println!("值: {}", element);
    }
    
    // 使用 Range
    for number in 1..4 {       // 1, 2, 3(不包括 4)
        println!("{}!", number);
    }
    
    // 反转 Range
    for number in (1..4).rev() {  // 3, 2, 1
        println!("{}!", number);
    }
    
    // 遍历集合
    let names = vec!["Alice", "Bob", "Charlie"];
    for name in names.iter() {
        println!("Hello, {}!", name);
    }
}

Demo 2.4:打印乘法表

fn main() {
    for i in 1..=9 {
        for j in 1..=i {
            print!("{}×{}\t", j, i);
        }
        println!();
    }
}

2.5 注释

fn main() {
    // 单行注释
    
    /*
     * 块注释
     * 可以跨越多行
     */
    
    /// 文档注释(对外 API)
    /// 支持 Markdown 语法
    /// 使用 `cargo doc` 生成文档
    
    //! 模块级文档注释
    //! 描述包含它的模块或 crate
    
    let x = 5; // 行尾注释
}

第三部分:所有权系统(核心!)

对应官方文档 Chapter 4: Understanding Ownership

3.1 什么是所有权?

所有权规则

  1. R
ust 中的每个值都有一个所有者(owner)
  1. 一
次只能有一个所有者
  1. 当
所有者离开作用域,值将被丢弃(drop)

为什么需要所有权?

传统语言管理内存的方式:

内存模型

栈 (Stack)                    堆 (Heap)
┌─────────────┐             ┌────────────────────┐
│ name: ptr   │ ──────────► │        h           │
│ len: 5      │             │        e           │
│ capacity: 5 │             │        l           │
└─────────────┘             │        l           │
String 元数据               │        o           │
                            └────────────────────┘
                            实际字符串数据
栈 vs 堆:

字符串字面量 vs String

fn main() {
    // 字符串字面量:固定大小,编译时已知,存储在栈上
    let s1 = "hello";
    // s1 是 &str(字符串切片),指向二进制文件中的数据
    // 不可变,编译时大小已知
    
    // String:可变,存储在堆上
    let s2 = String::from("hello");
    s2.push_str(", world!");  // 可变
    // String 在堆上分配,运行时大小可变
}

3.2 移动(Move)

浅拷贝 vs 深拷贝 vs 移动

fn main() {
    // 栈上的数据:复制(Copy)
    let x = 5;
    let y = x;  // 复制而非移动(整数实现了 Copy trait)
    println!("x = {}, y = {}", x, y);  // 都有效
    
    // 堆上的数据:移动(Move)
    let s1 = String::from("hello");
    let s2 = s1;  // s1 被"移动"到 s2,s1 不再有效
    
    // println!("{}", s1);  // ❌ 编译错误!s1 已被移动
    println!("{}", s2);     // ✅ 正确
}
为什么移动而不是复制?

克隆(Clone)

fn main() {
    let s1 = String::from("hello");
    let s2 = s1.clone();  // 深度复制(堆上的数据也被复制)
    
    println!("s1 = {}, s2 = {}", s1, s2);  // 都有效
}

Copy trait

fn main() {
    // 实现了 Copy trait 的类型:
    // - 所有整数类型(i32, u64 等)
    // - 浮点类型(f32, f64)
    // - 布尔类型(bool)
    // - 字符类型(char)
    // - 元组,如果所有元素都是 Copy 的
    
    let a = (1, 2.0);  // ✅ 元组内都是 Copy 类型
    let b = a;
    println!("a = {:?}, b = {:?}", a, b);  // 都有效
    
    let c = (1, String::from("hello"));  // ❌ String 不是 Copy
    let d = c;
    // println!("{:?}", c);  // ❌ c 已被移动
    println!("{:?}", d);     // ✅
}
Copy trait 的规则:

函数中的所有权

fn main() {
    let s = String::from("hello");
    takes_ownership(s);  // s 被移动到函数中
    // println!("{}", s);  // ❌ s 不再有效
    
    let x = 5;
    makes_copy(x);  // x 被复制到函数中
    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 离开作用域,没有特殊操作

返回值与作用域

fn main() {
    let s1 = gives_ownership();  // 返回值移动到 s1
    
    let s2 = String::from("hello");
    let s3 = takes_and_gives_back(s2);  // s2 移动到函数,返回值移动到 s3
    
    println!("s1 = {}, s3 = {}", s1, s3);
}

fn gives_ownership() -> String {
    let some_string = String::from("yours");
    some_string  // 返回值移动到调用者
}

fn takes_and_gives_back(a_string: String) -> String {
    a_string  // 返回值移动到调用者
}

Demo 3.1:所有权转移的完整示例

fn main() {
    // 场景:用户注册流程
    let username = String::from("alice");
    let email = String::from("alice@example.com");
    
    // 创建用户(所有权转移到 User 结构体)
    let user = create_user(username, email);
    
    // println!("{}", username);  // ❌ username 已被移动
    println!("用户创建成功: {:?}", user);
    
    // 更新邮箱(需要重新赋值)
    let user = update_email(user, String::from("newalice@example.com"));
    println!("更新后: {:?}", user);
}

#[derive(Debug)]
struct User {
    username: String,
    email: String,
}

fn create_user(username: String, email: String) -> User {
    User { username, email }
}

fn update_email(mut user: User, new_email: String) -> User {
    user.email = new_email;
    user
}

3.3 引用与借用

引用(Reference)

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

// &String 表示对 String 的引用
fn calculate_length(s: &String) -> usize {
    s.len()
}  // s 离开作用域但不释放内存(不拥有所有权)
     s1                    s
┌───────────┐         ┌───────────┐
│ ptr       │ ──────► │ ptr       │ ──► "hello"
│ len: 5    │         └───────────┘
│ cap: 5    │         引用(指针)
└───────────┘

可变引用(Mutable Reference)

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");
}

借用规则(核心!)

核心规则:
1. 同一时间,只能有一个可变引用
2. 或者可以有多个不可变引用
3. 引用必须始终有效
fn main() {
    let mut s = String::from("hello");
    
    // 多个不可变引用 - ✅ 允许
    let r1 = &s;
    let r2 = &s;
    println!("{} and {}", r1, r2);
    
    // ❌ 错误:不可变引用存在时不能有可变引用
    // let r3 = &mut s;
    // error[E0502]: cannot borrow `s` as mutable because it is also borrowed as immutable
    
    // ✅ 正确:在不可变引用不再使用后(NLL: Non-Lexical Lifetimes)
    let r3 = &mut s;
    println!("{}", r3);
}

悬垂引用(Dangling Reference)

// ❌ 编译错误!不能返回局部变量的引用
// fn dangle() -> &String {
//     let s = String::from("hello");
//     &s  // s 离开作用域被释放,引用指向无效内存
// }
// error[E0106]: missing lifetime specifier

// ✅ 正确:直接返回 String
fn no_dangle() -> String {
    let s = String::from("hello");
    s
}

Demo 3.2:引用的实际应用

fn main() {
    let mut numbers = vec![1, 2, 3, 4, 5];
    
    // 不可变借用:读取数据
    let first = &numbers[0];
    println!("第一个元素: {}", first);
    
    // 可变借用:修改数据
    for num in &mut numbers {
        *num *= 2;
    }
    println!("翻倍后: {:?}", numbers);
    
    // 使用引用避免所有权转移
    let sum = calculate_sum(&numbers);
    println!("总和: {}", sum);
    println!("numbers 仍然可用: {:?}", numbers);
}

fn calculate_sum(numbers: &[i32]) -> i32 {
    numbers.iter().sum()
}

3.4 切片(Slice)

字符串切片

fn main() {
    let s = String::from("hello world");
    
    let hello = &s[0..5];    // "hello"
    let world = &s[6..11];   // "world"
    let hello = &s[..5];     // 省略起始(从 0 开始)
    let world = &s[6..];     // 省略结束(到末尾)
    let whole = &s[..];      // 全部
    
    println!("{} {}", hello, world);
}

第一个单词函数

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 s = String::from("hello world");
    let word = first_word(&s);
    println!("第一个单词: {}", word);
}

其他类型的切片

fn main() {
    let a = [1, 2, 3, 4, 5];
    let slice = &a[1..3];  // [2, 3]
    assert_eq!(slice, &[2, 3]);
    
    // 切片是对连续序列的引用
    // 字符串切片 &str 和数组切片 &[T] 都是切片
}

Demo 3.3:字符串处理工具

fn main() {
    let text = "The quick brown fox jumps over the lazy dog";
    
    println!("原文: {}", text);
    println!("第一个单词: {}", first_word(text));
    println!("最后一个单词: {}", last_word(text));
    println!("单词数量: {}", count_words(text));
}

fn first_word(s: &str) -> &str {
    s.split_whitespace().next().unwrap_or("")
}

fn last_word(s: &str) -> &str {
    s.split_whitespace().last().unwrap_or("")
}

fn count_words(s: &str) -> usize {
    s.split_whitespace().count()
}

第四部分:结构体

对应官方文档 Chapter 5: Using Structs to Structure Related Data

4.1 定义与创建结构体

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

fn main() {
    // 创建实例(字段顺序可以不同,但名称必须匹配)
    let user1 = User {
        email: String::from("someone@example.com"),
        username: String::from("someusername"),
        active: true,
        sign_in_count: 1,
    };
    
    // 访问字段
    println!("用户名: {}", user1.username);
    
    // 可变实例(整个实例必须是可变的,不能只标记某些字段为 mut)
    let mut user2 = User {
        email: String::from("another@example.com"),
        username: String::from("anotherusername"),
        active: true,
        sign_in_count: 1,
    };
    user2.email = String::from("new@example.com");
}

字段初始化简写

fn build_user(email: String, username: String) -> User {
    User {
        email,           // email: email 的简写
        username,        // username: username 的简写
        active: true,
        sign_in_count: 1,
    }
}

从其他实例创建(结构体更新语法)

fn main() {
    let user1 = User {
        email: String::from("someone@example.com"),
        username: String::from("someusername"),
        active: true,
        sign_in_count: 1,
    };
    
    // 结构体更新语法(..user1)
    let user2 = User {
        email: String::from("another@example.com"),
        username: String::from("anotherusername"),
        ..user1  // 其余字段来自 user1
    };
    
    // ⚠️ 注意:如果 user1 的字段中有非 Copy 类型(如 String),
    // user1 的 username 字段会被移动到 user2
    // println!("{}", user1.username);  // ❌ 已被移动
    println!("{}", user1.active);  // ✅ bool 是 Copy 类型
}

元组结构体

// 元组结构体:有名称但没有命名字段
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 = ({}, {}, {})", black.0, black.1, black.2);
    println!("origin = ({}, {}, {})", origin.0, origin.1, origin.2);
    
    // 虽然 Color 和 Point 内部结构相同,但它们是不同的类型
    // let p: Point = black;  // ❌ 类型不匹配
}

单元结构体(Unit-Like Structs)

// 单元结构体:没有任何字段
// 常用于实现 trait 但不需要存储数据的情况
struct AlwaysEqual;

fn main() {
    let subject = AlwaysEqual;
    
    // 可以为其实现 trait
    // impl SomeTrait for AlwaysEqual { ... }
}

Demo 4.1:矩形面积计算

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

fn main() {
    let rect1 = Rectangle { width: 30, height: 50 };
    let rect2 = Rectangle { width: 10, height: 40 };
    let rect3 = Rectangle { width: 60, height: 45 };
    
    println!("rect1 的面积: {}", area(&rect1));
    println!("rect1: {:?}", rect1);  // 使用 Debug trait 打印
    
    println!("rect1 能容纳 rect2 吗?{}", rect1.can_hold(&rect2));
    println!("rect1 能容纳 rect3 吗?{}", rect1.can_hold(&rect3));
    
    // 使用关联函数创建正方形
    let sq = Rectangle::square(5);
    println!("正方形: {:?}", sq);
}

fn area(rectangle: &Rectangle) -> u32 {
    rectangle.width * rectangle.height
}

// 为结构体实现方法
impl Rectangle {
    // &self 是 self: &Self 的简写
    fn can_hold(&self, other: &Rectangle) -> bool {
        self.width > other.width && self.height > other.height
    }
    
    // 关联函数(没有 self 参数)
    fn square(size: u32) -> Self {
        Self {
            width: size,
            height: size,
        }
    }
}

4.2 方法(Method)

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

// 实现块:定义方法
impl Rectangle {
    // 不可变方法
    fn area(&self) -> u32 {
        self.width * self.height
    }
    
    // 可变方法
    fn resize(&mut self, width: u32, height: u32) {
        self.width = width;
        self.height = height;
    }
    
    // 消耗 self 的方法
    fn destroy(self) {
        println!("销毁矩形: {}x{}", self.width, self.height);
    }
    
    // 关联函数(没有 self)
    fn square(size: u32) -> Self {
        Self {
            width: size,
            height: size,
        }
    }
}

// 一个类型可以有多个 impl 块(功能上等价于一个)
impl Rectangle {
    fn perimeter(&self) -> u32 {
        2 * (self.width + self.height)
    }
}

fn main() {
    let mut rect = Rectangle { width: 30, height: 50 };
    println!("面积: {}", rect.area());
    println!("周长: {}", rect.perimeter());
    
    rect.resize(40, 60);
    println!("调整后面积: {}", rect.area());
    
    let sq = Rectangle::square(10);
    println!("正方形: {:?}", sq);
    
    rect.destroy();
    // rect.area();  // ❌ rect 已被销毁
}

self 参数的类型

方法签名等价于效果
fn f(&self)fn f(self: &Self)不可变借用
fn f(&mut self)fn f(self: &mut Self)可变借用
fn f(self)fn f(self: Self)获取所有权

自动引用和解引用

// Rust 会自动添加 &、&mut 或 * 来匹配方法签名
let rect = Rectangle { width: 1, height: 2 };
rect.area();          // 等价于 (&rect).area()
(&rect).area();       // 显式借用
(&mut rect).resize(3, 4);  // 显式可变借用

第五部分:枚举与模式匹配

对应官方文档 Chapter 6: Enums and Pattern Matching

5.1 定义枚举

// 基本枚举
enum IpAddrKind {
    V4,
    V6,
}

// 带数据的枚举
enum IpAddr {
    V4(u8, u8, u8, u8),
    V6(String),
}

// 枚举可以包含不同类型和数量的数据
enum Message {
    Quit,                       // 无数据
    Move { x: i32, y: i32 },    // 匿名结构体
    Write(String),              // 单个 String
    ChangeColor(i32, i32, i32), // 三个 i32
}

// 枚举也可以有 impl 块
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!("颜色: ({}, {}, {})", r, g, b),
        }
    }
}

fn main() {
    let home = IpAddr::V4(127, 0, 0, 1);
    let loopback = IpAddr::V6(String::from("::1"));
    
    let m = Message::Write(String::from("hello"));
    m.call();
}

Option 枚举

// Rust 没有 null,而是用 Option 枚举
// 定义在标准库中:
// enum Option<T> {
//     None,      // 空值
//     Some(T),   // 有值
// }

fn main() {
    let some_number = Some(5);
    let some_string = Some("a string");
    let absent_number: Option<i32> = None;
    
    // 使用 Option 避免 null 引用错误
    // 必须处理 None 情况才能使用值
}
为什么 Option 比 null 安全?

5.2 match 模式匹配

#[derive(Debug)]
enum UsState {
    Alabama,
    Alaska,
    // ...
}

enum Coin {
    Penny,
    Nickel,
    Dime,
    Quarter(UsState),
}

fn value_in_cents(coin: Coin) -> u8 {
    match coin {
        Coin::Penny => {
            println!("幸运硬币!");
            1
        }
        Coin::Nickel => 5,
        Coin::Dime => 10,
        Coin::Quarter(state) => {
            println!("来自 {:?} 的 quarter!", state);
            25
        }
    }
}

fn main() {
    let coin = Coin::Quarter(UsState::Alaska);
    println!("价值: {} 分", value_in_cents(coin));
}

match 必须穷尽所有可能

fn plus_one(x: Option<i32>) -> Option<i32> {
    match x {
        None => None,
        Some(i) => Some(i + 1),
    }
    // 如果遗漏 None 分支,编译器会报错
}

fn main() {
    let five = Some(5);
    let six = plus_one(five);
    let none = plus_one(None);
    println!("six = {:?}, none = {:?}", six, none);
}

占位符 _

fn main() {
    let dice_roll = 9;
    match dice_roll {
        3 => add_fancy_hat(),
        7 => remove_fancy_hat(),
        other => move_player(other),  // 捕获所有其他值
    }
    
    match dice_roll {
        3 => add_fancy_hat(),
        7 => remove_fancy_hat(),
        _ => reroll(),  // 不关心其他值,但不绑定
    }
    
    match dice_roll {
        3 => add_fancy_hat(),
        _ => (),  // 什么都不做(unit 类型)
    }
}

fn add_fancy_hat() {}
fn remove_fancy_hat() {}
fn move_player(num_spaces: u8) {}
fn reroll() {}

使用 match 处理 Option

fn main() {
    let five = Some(5);
    let six = plus_one(five);
    let none = plus_one(None);
}

fn plus_one(x: Option<i32>) -> Option<i32> {
    match x {
        None => None,
        Some(i) => Some(i + 1),
    }
}

5.3 if let 简化匹配

fn main() {
    let config_max = Some(3u8);
    
    // 完整 match
    match config_max {
        Some(max) => println!("最大值被设置为 {}", max),
        _ => (),
    }
    
    // 简化写法:if let
    if let Some(max) = config_max {
        println!("最大值被设置为 {}", max);
    }
    
    // 带 else
    let coin = Coin::Penny;
    let mut count = 0;
    if let Coin::Quarter(state) = coin {
        println!("来自 {:?} 的 quarter!", state);
    } else {
        count += 1;
    }
}

Demo 5.1:解析配置值

fn main() {
    let config = Config {
        debug: true,
        log_level: Some("info".to_string()),
        port: Some(8080),
        host: None,
    };
    
    println!("调试模式: {}", config.debug);
    
    // 使用 if let 处理 Option
    if let Some(level) = &config.log_level {
        println!("日志级别: {}", level);
    } else {
        println!("日志级别: 未设置");
    }
    
    if let Some(port) = config.port {
        println!("端口: {}",port);
    }
    
    if let Some(host) = &config.host {
        println!("主机: {}", host);
    } else {
        println!("主机: 默认 (localhost)");
    }
}

struct Config {
    debug: bool,
    log_level: Option<String>,
    port: Option<u16>,
    host: Option<String>,
}

第六部分:包、Crate 和模块

对应官方文档 Chapter 7: Managing Growing Projects with Packages, Crates, and Modules

6.1 包与 Crate

层次结构

包 (Package)
├── Cargo.toml          # 包配置文件
└── src/
    ├── main.rs         # 二进制 crate 根(入口)
    ├── lib.rs          # 库 crate 根
    └── bin/            # 额外的二进制 crate
        └── extra.rs
规则:

Crate 的类型


6.2 定义模块

// src/lib.rs
mod front_of_house {
    mod hosting {
        fn add_to_waitlist() {}
        fn seat_at_table() {}
    }
    
    mod serving {
        fn take_order() {}
        fn serve_order() {}
        fn take_payment() {}
    }
}

模块树

crate
 └── front_of_house
     ├── hosting
     │   ├── add_to_waitlist
     │   └── seat_at_table
     └── serving
         ├── take_order
         ├── serve_order
         └── take_payment

6.3 路径(Paths)

绝对路径和相对路径

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

pub fn eat_at_restaurant() {
    // 绝对路径(从 crate 根开始)
    crate::front_of_house::hosting::add_to_waitlist();
    
    // 相对路径(从当前模块开始)
    front_of_house::hosting::add_to_waitlist();
}

super 关键字

fn deliver_order() {}

mod back_of_house {
    fn fix_incorrect_order() {
        cook_order();
        super::deliver_order();  // 访问父模块的函数
    }
    
    fn cook_order() {}
}

pub 关键字

mod back_of_house {
    pub struct Breakfast {
        pub toast: String,
        seasonal_fruit: String,  // 私有字段
    }
    
    impl Breakfast {
        pub fn summer(toast: &str) -> Breakfast {
            Breakfast {
                toast: String::from(toast),
                seasonal_fruit: String::from("peaches"),
            }
        }
    }
    
    // 枚举的变体在枚举为 pub 时自动为 pub
    pub enum Appetizer {
        Soup,
        Salad,
    }
}

pub fn eat_at_restaurant() {
    let mut meal = back_of_house::Breakfast::summer("Rye");
    meal.toast = String::from("Wheat");
    println!("请给我 {:?} 面包", meal.toast);
    
    // ❌ 错误:seasonal_fruit 是私有的
    // meal.seasonal_fruit = String::from("blueberries");
}
默认私有规则:

6.4 use 关键字

引入

--- 鎺ョ画 ---

Mutex

use std::sync::Mutex;

fn main() {
    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;

fn main() {
    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());
}

Send 鍜?Sync

// Send: 鍙互鍦ㄧ嚎绋嬮棿杞Щ鎵€鏈夋潈
// Sync: 鍙互鍦ㄧ嚎绋嬮棿鍏变韩寮曠敤锛?T 鏄?Send锛?

// Rust 鑷姩涓哄ぇ澶氭暟绫诲瀷瀹炵幇 Send 鍜?Sync
// 鍘熷鎸囬拡 *const T 鍜?*mut T 娌℃湁瀹炵幇 Send 鍜?Sync

Demo 13.1锛氬绾跨▼涓嬭浇鍣紙妯℃嫙锛?

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

fn main() {
    let urls = vec![
        "https://example.com/file1.txt",
        "https://example.com/file2.txt",
        "https://example.com/file3.txt",
        "https://example.com/file4.txt",
    ];
    
    let results = Arc::new(Mutex::new(Vec::new()));
    let mut handles = vec![];
    
    for url in urls {
        let results = Arc::clone(&results);
        let handle = thread::spawn(move || {
            // 妯℃嫙涓嬭浇
            println!("寮€濮嬩笅杞? {}", url);
            thread::sleep(Duration::from_millis(100));
            let content = format!("{} 鐨勫唴瀹?, url);
            results.lock().unwrap().push(content);
            println!("瀹屾垚涓嬭浇: {}", url);
        });
        handles.push(handle);
    }
    
    for handle in handles {
        handle.join().unwrap();
    }
    
    let results = results.lock().unwrap();
    println!("涓嬭浇瀹屾垚锛屽叡 {} 涓枃浠?", results.len());
    for content in results.iter() {
        println!("  - {}", content);
    }
}

绗崄鍥涢儴鍒嗭細楂樼骇鐗规€?

14.1 涓嶅畨鍏?Rust

瀵瑰簲瀹樻柟鏂囨。 Chapter 20.1: Unsafe Rust
fn main() {
    let mut num = 5;
    
    // 鍘熷鎸囬拡
    let r1 = &num as *const i32;
    let r2 = &mut num as *mut i32;
    
    // 瑙e紩鐢ㄥ師濮嬫寚閽堥渶瑕?unsafe
    unsafe {
        println!("r1 鏄? {}", *r1);
        println!("r2 鏄? {}", *r2);
    }
    
    // 璋冪敤涓嶅畨鍏ㄥ嚱鏁?
    unsafe {
        dangerous();
    }
    
    // 瀹夊叏鎶借薄
    let mut v = vec![1, 2, 3, 4, 5, 6];
    let r = &mut v[..];
    let (a, b) = split_at_mut(r, 3);
    
    assert_eq!(a, &mut [1, 2, 3]);
    assert_eq!(b, &mut [4, 5, 6]);
}

unsafe fn dangerous() {}

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 {
        (
            std::slice::from_raw_parts_mut(ptr, mid),
            std::slice::from_raw_parts_mut(ptr.add(mid), len - mid),
        )
    }
}
*涓嶅畨鍏?Rust 鐨勮兘鍔?锛?
  1. 瑙
e紩鐢ㄥ師濮嬫寚閽?
  1. 璋
冪敤涓嶅畨鍏ㄥ嚱鏁版垨鏂规硶
  1. 璁
块棶鎴栦慨鏀瑰彲鍙橀潤鎬佸彉閲?
  1. 瀹
炵幇涓嶅畨鍏?trait
  1. 璁
块棶 union 鐨勫瓧娈? *浣跨敤 unsafe 鐨勫父瑙佸満鏅?锛?

extern 鍑芥暟

// 璋冪敤澶栭儴 C 浠g爜
extern "C" {
    fn abs(input: i32) -> i32;
}

fn main() {
    unsafe {
        println!("C 鐨勭粷瀵瑰€? {}", abs(-3));
    }
}

// 瀵煎嚭 Rust 鍑芥暟缁?C 浣跨敤
#[no_mangle]
pub extern "C" fn call_from_c() {
    println!("鏉ヨ嚜 C 鐨勮皟鐢?);
}

14.2 楂樼骇 Trait

鍏宠仈绫诲瀷

pub trait Iterator {
    type Item;  // 鍏宠仈绫诲瀷
    
    fn next(&mut self) -> Option<Self::Item>;
}

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> {
        self.count += 1;
        if self.count < 6 {
            Some(self.count)
        } else {
            None
        }
    }
}

榛樿娉涘瀷鍙傛暟

use std::ops::Add;

#[derive(Debug, PartialEq)]
struct Millimeters(u32);
struct Meters(u32);

impl Add<Meters> for Millimeters {
    type Output = Millimeters;
    
    fn add(self, other: Meters) -> Millimeters {
        Millimeters(self.0 + (other.0 * 1000))
    }
}

瀹屽叏闄愬畾璇硶

trait Pilot {
    fn fly(&self);
}

trait Wizard {
    fn fly(&self);
}

struct Human;

impl Pilot for Human {
    fn fly(&self) {
        println!("鏈洪暱璇翠綘濂?);
    }
}

impl Wizard for Human {
    fn fly(&self) {
        println!("璧烽锛?);
    }
}

impl Human {
    fn fly(&self) {
        println!("鎸ユ墜");
    }
}

fn main() {
    let person = Human;
    person.fly();           // 榛樿璋冪敤 Human 鐨勬柟娉?
    Pilot::fly(&person);    // 璋冪敤 Pilot trait
    Wizard::fly(&person);   // 璋冪敤 Wizard trait
}

// 瀹屽叏闄愬畾璇硶
// <Type as Trait>::function(receiver_if_method, next_arg, ...);

Supertrait

use std::fmt;

trait PrintOutline: fmt::Display {
    fn print_outline(&self) {
        let output = self.to_string();
        let len = output.len();
        println!("{}", "*".repeat(len + 4));
        println!("* {} *", output);
        println!("{}", "*".repeat(len + 4));
    }
}

newtype 妯″紡

use std::fmt;

struct Wrapper(Vec<String>);

impl fmt::Display for Wrapper {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "[{}]", self.0.join(", "))
    }
}

fn main() {
    let w = Wrapper(vec![String::from("hello"), String::from("world")]);
    println!("w = {}", w);
}

14.3 楂樼骇绫诲瀷

绫诲瀷鍒悕

type Kilometers = i32;

fn main() {
    let x: i32 = 5;
    let y: Kilometers = 5;
    println!("x + y = {}", x + y);
}

// 鐢ㄩ€旓細鍑忓皯閲嶅
type Thunk = Box<dyn Fn() + Send + 'static>;

fn takes_long_type(f: Thunk) {
    // ...
}

fn returns_long_type() -> Thunk {
    Box::new(|| println!("hi"))
}

Never 绫诲瀷

// ! 绫诲瀷锛坣ever type锛夎〃绀烘案涓嶈繑鍥?
fn bar() -> ! {
    panic!()
}

// 鐢ㄩ€旓細continue銆乸anic!銆乴oop + break

14.4 楂樼骇鍑芥暟涓庨棴鍖?

鍑芥暟鎸囬拡

fn add_one(x: i32) -> i32 {
    x + 1
}

fn do_twice(f: fn(i32) -> i32, arg: i32) -> i32 {
    f(arg) + f(arg)
}

fn main() {
    let answer = do_twice(add_one, 5);
    println!("绛旀鏄? {}", answer);  // 12
    
    // fn 鏄竴涓被鍨嬶紝瀹炵幇浜嗘墍鏈?Fn trait
    let list_of_numbers = vec![1, 2, 3];
    let list_of_strings: Vec<String> = list_of_numbers
        .iter()
        .map(|i| i.to_string())
        .collect();
    
    // 涔熷彲浠ヤ娇鐢ㄥ嚱鏁版寚閽?
    let list_of_strings: Vec<String> = list_of_numbers
        .iter()
        .map(ToString::to_string)
        .collect();
}

杩斿洖闂寘

// 鉂?閿欒锛氶棴鍖呭ぇ灏忔湭鐭?
// fn returns_closure() -> dyn Fn(i32) -> i32 {
//     |x| x + 1
// }

// 鉁?姝g‘锛氫娇鐢?Box 鍖呰
fn returns_closure() -> Box<dyn Fn(i32) -> i32> {
    Box::new(|x| x + 1)
}

14.5 瀹?

瀵瑰簲瀹樻柟鏂囨。 Chapter 20.5: Macros

澹版槑瀹忥紙macro_rules!锛?

// 绠€鍖栫殑 vec! 瀹?
#[macro_export]
macro_rules! vec {
    ( $( $x:expr ),* ) => {
        {
            let mut temp_vec = Vec::new();
            $(
                temp_vec.push($x);
            )*
            temp_vec
        }
    };
}

fn main() {
    let v = vec![1, 2, 3];
    println!("{:?}", v);
}

杩囩▼瀹?

// 杩囩▼瀹忕殑瀹氫箟鍦ㄥ崟鐙殑 crate 涓?
// 鏈変笁绉嶇被鍨嬶細
// 1. 绫诲睘鎬ц繃绋嬪畯锛坉erive锛?
// 2. 绫诲嚱鏁拌繃绋嬪畯
// 3. 绫诲睘鎬у畯

// 浣跨敤 derive 鐨勪緥瀛?
#[derive(Debug, Clone, PartialEq)]
struct Point {
    x: i32,
    y: i32,
}

// derive 鑷姩鐢熸垚 trait 瀹炵幇

缂栧啓鑷畾涔?derive 瀹?

// hello_macro.rs
pub trait HelloMacro {
    fn hello_macro();
}

// hello_macro_derive.rs锛堝崟鐙殑 proc-macro crate锛?
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::DeriveImpl) -> 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()
}

绗崄浜旈儴鍒嗭細甯哥敤妯″紡

瀵瑰簲瀹樻柟鏂囨。 Chapter 19: Patterns and Matching

15.1 妯″紡鍖归厤璇硶

fn main() {
    // 瀛楅潰閲?
    let x = 1;
    match x {
        1 => println!("one"),
        2 => println!("two"),
        _ => println!("other"),
    }
    
    // 鍛藉悕鍙橀噺
    let x = Some(5);
    let y = 10;
    match x {
        Some(50) => println!("Got 50"),
        Some(y) => println!("Matched, y = {:?}", y),
        _ => println!("Default case, x = {:?}", x),
    }
    
    // 澶氭ā寮?
    let x = 1;
    match x {
        1 | 2 => println!("one or two"),
        _ => println!("other"),
    }
    
    // 鑼冨洿
    let x = 5;
    match x {
        1..=5 => println!("one through five"),
        _ => println!("other"),
    }
    
    // 瑙f瀯缁撴瀯浣?
    struct Point { x: i32, y: i32 }
    let p = Point { x: 0, y: 7 };
    let Point { x: a, y: b } = p;
    
    // 绠€鍐?
    let Point { x, y } = p;
    
    // 瑙f瀯鏋氫妇
    enum Message {
        Quit,
        Move { x: i32, y: i32 },
        Write(String),
        ChangeColor(i32, i32, i32),
    }
    
    let msg = Message::ChangeColor(0, 160, 255);
    match msg {
        Message::Quit => println!("Quit"),
        Message::Move { x, y } => println!("Move to ({}, {})", x, y),
        Message::Write(text) => println!("Write: {}", text),
        Message::ChangeColor(r, g, b) => println!("Color ({}, {}, {})", r, g, b),
    }
    
    // 宓屽瑙f瀯
    let num = 4u8;
    match num {
        1 => println!("One"),
        2 | 3 | 5 | 7 | 11 => println!("This is a prime"),
        13..=19 => println!("A teen"),
        _ => println!("Ain't special"),
    }
    
    // 蹇界暐鍊?
    let mut setting_value = Some(5);
    let new_setting_value = Some(10);
    match (setting_value, new_setting_value) {
        (Some(_), Some(_)) => println!("Can't overwrite"),
        _ => setting_value = new_setting_value,
    }
    
    // .. 蹇界暐鍓╀綑閮ㄥ垎
    struct Point3D { x: i32, y: i32, z: i32 }
    let origin = Point3D { x: 0, y: 0, z: 0 };
    match origin {
        Point3D { x, .. } => println!("x is {}", x),
    }
    
    // 鍖归厤瀹堝崼
    let num = Some(4);
    match num {
        Some(x) if x % 2 == 0 => println!("Even"),
        Some(x) => println!("Odd"),
        None => (),
    }
    
    // @ 缁戝畾
    enum Greeting { Hello { id: i32 } }
    let msg = Greeting::Hello { id: 5 };
    match msg {
        Greeting::Hello { id: id_variable @ 3..=7 } => println!("Found an id in range: {}", id_variable),
        Greeting::Hello { id: 10..=12 } => println!("Found an id in another range"),
        Greeting::Hello { id } => println!("Found some other id: {}", id),
    }
}

let-else锛圧ust 1.65+锛?

fn main() {
    let Some(x) = Some(5) else {
        return;
    };
    println!("x = {}", x);
}

15.2 let 璇彞涓殑妯″紡

fn main() {
    // 鍏冪粍瑙f瀯
    let (x, y, z) = (1, 2, 3);
    
    // 鍑芥暟鍙傛暟涓殑妯″紡
    let point = (3, 5);
    print_coordinates(&point);
}

fn print_coordinates(&(x, y): &(i32, i32)) {
    println!("褰撳墠鍧愭爣: ({}, {})", x, y);
}

闄勫綍

A. Rust 缂栫爜瑙勮寖

鍛藉悕瑙勮寖

绫诲瀷瑙勮寖绀轰緥
鍙橀噺snake_caseuser_name
鍑芥暟snake_caseget_user
缁撴瀯浣?PascalCaseUserName
鏋氫妇PascalCaseColor
traitPascalCasePrintable
甯搁噺SCREAMING_SNAKE_CASEMAX_SIZE
妯″潡snake_caseuser_module
瀹?snake_case!println!

鏍煎紡鍖?

# 鏍煎紡鍖栦唬鐮?
cargo fmt

# 妫€鏌ヤ絾涓嶄慨鏀?
cargo fmt --check

# 杩愯 clippy 妫€鏌?
cargo clippy

B. 甯哥敤 Cargo 鍛戒护

# 鏂板缓椤圭洰
cargo new project_name
cargo new --lib lib_name

# 鏋勫缓
cargo build            # debug 妯″紡
cargo build --release  # release 妯″紡锛堜紭鍖栵級

# 杩愯
cargo run

# 妫€鏌ョ紪璇戦敊璇紙涓嶇敓鎴愬彲鎵ц鏂囦欢锛屾洿蹇級
cargo check

# 杩愯娴嬭瘯
cargo test

# 鐢熸垚鏂囨。
cargo doc --open

# 娣诲姞渚濊禆
cargo add package_name

# 鏇存柊渚濊禆
cargo update

# 娓呯悊鏋勫缓
cargo clean

# 鏋勫缓鐗瑰畾鐩爣
cargo build --target x86_64-pc-windows-msvc

C. 閿欒淇℃伅瑙h

閿欒绫诲瀷鍚箟瑙e喅鏂规
cannot borrow as mutable璇曞浘鍙彉鍊熺敤涓嶅彲鍙樺彉閲?娣诲姞 mut
value used after move浣跨敤宸茬Щ鍔ㄧ殑鍊?浣跨敤 clone() 鎴栧紩鐢?
lifetime mismatch鐢熷懡鍛ㄦ湡涓嶅尮閰?娣诲姞鐢熷懡鍛ㄦ湡鏍囨敞
trait not implemented缂哄皯 trait 瀹炵幇瀹炵幇鐩稿簲 trait 鎴栦娇鐢?derive
unused variable鏈娇鐢ㄧ殑鍙橀噺浣跨敤 _ 鍓嶇紑鎴栧垹闄?
expected type, found绫诲瀷涓嶅尮閰?妫€鏌ョ被鍨嬫爣娉?
cannot infer type鏃犳硶鎺ㄦ柇绫诲瀷娣诲姞绫诲瀷鏍囨敞

D. 瀛︿範璧勬簮姹囨€?

鍏嶈垂鍦ㄧ嚎璧勬簮

  1. <
em>*Rust 鍦g粡锛圱he Rust Programming Language锛?
  1. <
strong>Rust by Example
  1. <
strong>Rustlings
  1. <
em>*Rust 鍦ㄧ嚎缂栬緫鍣?
  1. <
em>*Rust 鏍囧噯搴撴枃妗?

鎺ㄨ崘涔︾睄

绀惧尯


*绁濆涔犳剦蹇紒Rust 鏄竴闂ㄥ€煎緱鎶曞叆瀛︿範鐨勮瑷€銆? 馃