rust
2025年1月1日
Learn Rust in a Month of Lunches
胡喝海吃一个月,学会Rust?

Learn Rust in a Month of Lunches
本书涵盖了Rust编程语言的方方面面。它从基础概念如变量、数据类型和内存管理开始,逐步深入到更高级的主题,例如所有权、生命周期、错误处理、并发编程和异步编程。书中包含大量的代码示例和练习,旨在帮助读者在短时间内掌握Rust编程。此外,书中还介绍了一些常用的外部库,以及如何使用Cargo构建和管理Rust项目。
第一章:Rust 基础入门
- 核心概念: 本章主要介绍了 Rust 的基本语法和概念,包括变量声明、代码块、打印输出、类型转换和字符串。
- 变量与代码块:
- 使用
let
关键字声明变量,代码块用{}
表示。变量的作用域(lifetime)限制在代码块内部。 - Shadowing (遮蔽) 是指用新的
let
绑定同名变量,使之前的变量失效。 - 变量的类型通常由 Rust 自动推断,但可以使用
as
关键字进行显式类型转换。
- 使用
- 打印输出:
println!
宏用于打印输出,{}
用来捕获变量的值。{:?}
用于调试输出,{:#?}
用于更美观的调试输出,可以分行显示结构体等复杂类型的内容。print!
宏与println!
类似,但不添加换行符。- 可以使用
r#""#
来创建原始字符串,避免转义字符的麻烦。 - 在字符串前加
b
可以打印字符串的字节表示。
- 字符串类型:
&str
是一种字符串切片类型,后续章节会详细介绍。
第二章:内存、变量与所有权
- 核心概念: 本章深入探讨了 Rust 的内存管理机制,包括所有权、借用和引用。
- 所有权: Rust 通过所有权系统来管理内存,每个值都有一个所有者。
- 引用:
- 不可变引用(
&
)允许多个读取者同时访问数据,但不能修改。 - 可变引用(
&mut
)允许一个写入者修改数据,但不能同时存在其他引用。
- 不可变引用(
- 打印输出格式化:
{:}
用于显示打印,{:?}
用于debug打印,{:#?}
用于美化debug打印。可以使用"{:padding_char^min_length}"
来控制打印的对齐和填充。- 例如,
println!("{:ㅎ^11}", letter);
会在字母 “a” 的左右两侧填充韩文字符 ㅎ,总长度为 11。
- 例如,
第三章:更复杂的类型
- 核心概念: 本章介绍了 Rust 中更复杂的数据类型和控制流,包括元组、枚举、结构体、
if
语句、match
语句和循环。 - 元组: 元组可以将多个不同类型的值组合在一起。可以使用
_
忽略元组中不需要的值。 - 控制流:
if
语句用于根据条件执行代码块。match
语句用于模式匹配,可以根据不同的值执行不同的代码块。可以使用_
作为通配符,匹配其他情况。if
关键字可以用于match
语句中进行条件匹配。- 循环包括
loop
、for
等,loop
会一直循环直到break
。for
循环可以迭代一个范围,如0..3
(不包含3) 和0..=3
(包含3)。
- 结构体:
- 结构体 (struct) 用于将多个相关的值组合成一个数据结构。可以使用
struct ColorRgb(u8, u8, u8);
定义一个元组结构体,也可以使用struct SizeAndColor { size: u32, color: ColorRgb, }
定义一个命名结构体。
- 结构体 (struct) 用于将多个相关的值组合成一个数据结构。可以使用
- 枚举:
- 枚举 (enum) 用于定义一组可能的值,例如
enum ThingsInTheSky { Sun, Stars, }
。可以使用::
来选择枚举的变体。
- 枚举 (enum) 用于定义一组可能的值,例如
- 核心概念: 本章介绍了 Rust 中更复杂的数据类型和控制流,包括元组、枚举、结构体、
第四章:构建自定义类型
- 核心概念: 本章继续深入探讨了 Rust 的自定义类型,包括如何在枚举中存储数据,以及
use
关键字的用法。 - 枚举变体中的数据: 枚举的变体可以携带数据,例如
enum Number { U32(u32), I32(i32), }
。 use
关键字:use
关键字用于简化代码,可以导入枚举的变体。use
可以避免在使用枚举变体时重复书写枚举名称。use std::mem::size_of_val;
可以使用size_of_val()
函数,而无需每次都写std::mem::
。
- 核心概念: 本章继续深入探讨了 Rust 的自定义类型,包括如何在枚举中存储数据,以及
第五章:泛型、Option 和 Result
- 核心概念: 本章介绍了 Rust 的泛型、
Option
和Result
类型,用于编写更灵活、更健壮的代码。 - 泛型: 泛型允许函数或结构体接受多种类型,可以使用
<T>
来声明泛型类型。where
关键字用于在泛型类型上添加约束,例如where T: Display
表示T
必须实现Display
trait。 Option
类型:Option
类型用于处理可能为空的值,它有两个变体:Some(T)
和None
。Result
类型:Result
类型用于处理可能失败的操作,它有两个变体:Ok(T)
和Err(E)
。Err
变体通常包含描述错误信息的类型。- 模式匹配: 可以使用
match
语句对Option
和Result
类型进行模式匹配,处理不同的情况。
- 核心概念: 本章介绍了 Rust 的泛型、
第六章:更多集合类型和错误处理
- 核心概念: 本章介绍了更多的集合类型和 Rust 的错误处理机制,包括
?
运算符和panic!
宏。 ?
运算符:?
运算符用于简化Result
类型的错误处理,如果结果是Ok
,则返回其值,否则提前返回错误。panic!
宏:panic!
宏用于抛出不可恢复的错误,程序会终止。assert!
、assert_eq!
和assert_ne!
宏用于在测试中检查条件是否满足。- 集合类型: 本章提到 Rust 还有很多集合类型,例如
BinaryHeap
(二叉堆), 但没有详细介绍。
- 核心概念: 本章介绍了更多的集合类型和 Rust 的错误处理机制,包括
第七章:Traits:让不同的类型做相同的事
- 核心概念: 本章重点介绍了 Rust 的 trait,用于定义共享行为,实现多态。
- Traits: Traits 可以被不同的类型实现,从而实现代码的复用,类似于其他语言的接口 (interface)。
T: Display
表示类型T
必须实现Display
trait。 unwrap_or
和unwrap_or_else
方法:unwrap_or
方法在Option
为None
或Result
为Err
时返回一个默认值。unwrap_or_else
方法则接收一个闭包来生成默认值。- 生命周期:
'a
表示生命周期,例如struct City<'a> { name: &'a str, date_founded: u32 }
,表示name
的生命周期至少与City
结构体一样长。
第十章:生命周期
- 核心概念: 本章主要探讨了生命周期和内部可变性。
- 生命周期: 生命周期用于确保引用不会悬空,
<'a>
用于声明生命周期。 - 内部可变性:
Cell
,RefCell
,Mutex
和RwLock
这些类型提供了内部可变性,允许在不可变类型中修改数据。Cell
类型用于包装实现了Copy
trait 的类型,可以使用.get()
和.set()
方法修改其值。RefCell
类型使用.borrow()
和.borrow_mut()
方法提供运行时借用检查,允许多个不可变借用或一个可变借用。Mutex
和RwLock
类型用于多线程编程,保证线程安全地访问共享数据。Mutex
提供互斥访问,RwLock
提供读写锁,允许多个读操作或一个写操作。
第十一章:多线程及其他
- 核心概念: 本章涵盖了多线程、
todo!
宏、类型别名、Cow
类型和Rc
类型等主题。 - 多线程: 可以使用
std::thread::spawn()
创建新线程,使用JoinHandle
等待线程结束。move
关键字用于将变量的所有权转移到闭包中。 todo!
宏:todo!
宏用于标记代码中尚未实现的部分,让编译器暂时忽略错误。- 类型别名: 使用
type
关键字创建类型别名,可以给现有类型取一个新名字。 Cow
类型:Cow
类型(Copy-on-Write)用于处理借用或拥有的数据,可以在需要时进行复制,提高效率。Rc
类型:Rc
类型(Reference Counting)用于在多个所有者之间共享数据,当最后一个Rc
实例被删除时,数据会被释放。
- 核心概念: 本章涵盖了多线程、
第十二章:闭包、泛型和线程
- 核心概念: 本章深入探讨了闭包、泛型和线程,并介绍了闭包的三种 trait:
Fn
、FnMut
和FnOnce
。 - 闭包: 闭包是一种可以捕获环境的匿名函数,具有三种 trait:
Fn
:捕获环境中的不可变引用。FnMut
:捕获环境中的可变引用。FnOnce
:捕获环境中的值,只能调用一次。
- 闭包作为参数: 函数可以接受闭包作为参数,并使用泛型来指定闭包的 trait。可以使用
impl Trait
来表示返回闭包的函数。 - 线程: 本章继续讨论了线程,主要介绍了如何使用闭包在线程中执行代码。
- 核心概念: 本章深入探讨了闭包、泛型和线程,并介绍了闭包的三种 trait:
第十三章:Box 和 Rust 文档
- 核心概念: 本章介绍了
Box
类型、如何阅读 Rust 文档,以及一些高级错误处理技巧。 Box
类型:Box
类型用于在堆上分配内存,例如Box<dyn Error>
用于存储实现了Error
trait 的类型。- 读取 Rust 文档: Rust 文档可以使用
cargo doc
命令生成。可以通过点击[src]
查看源代码。 - 高级错误处理: 可以使用
thiserror
crate 创建自定义错误类型,并使用#[from]
注解简化错误转换。还可以使用 blanket trait implementations 来处理所有实现了std::error::Error
的类型。
- 核心概念: 本章介绍了
第十四章:测试和从测试构建代码
- 核心概念: 本章介绍了 Rust 的测试框架和如何使用测试驱动开发 (TDD) 方法构建代码。
- 测试: 可以使用
#[test]
注解标记测试函数。assert_eq!
宏用于检查两个值是否相等,#[should_panic]
注解用于标记应该 panic 的测试。 - 测试驱动开发 (TDD): 本章通过一个简单的减法计算器例子,说明了如何先写测试,再实现代码。
第十五章:Default、构建者模式和 Deref
- 核心概念: 本章介绍了
Default
trait、构建者模式和Deref
trait。 Default
trait:Default
trait 用于为类型提供默认值,可以使用::default()
方法获取默认值。- 构建者模式: 构建者模式用于创建复杂对象,提供链式调用的方法来设置对象的属性。
Deref
和DerefMut
trait:Deref
trait 允许像使用原始类型一样使用智能指针。DerefMut
trait 允许可变借用 。
- 核心概念: 本章介绍了
第十六章:Const、”unsafe” Rust 和外部包
- 核心概念: 本章介绍了
const
、unsafe
Rust 和如何使用外部 crate。 const
:const
关键字用于定义常量,const
可以用于泛型参数 。const fn
用于声明可以在编译时求值的函数 。unsafe
Rust:unsafe
关键字用于标记不安全的 Rust 代码,例如直接操作内存 。- 外部包: 可以使用
Cargo.toml
文件管理项目依赖,并使用use
关键字导入外部 crate 的模块。
- 核心概念: 本章介绍了
第十七章:Anyhow 和 Thiserror
- 核心概念: 本章介绍了
Anyhow
和Thiserror
两个常用的错误处理 crate。 Anyhow
:Anyhow
提供了anyhow::Error
类型,用于快速处理错误。anyhow!
宏用于快速创建错误。Thiserror
:Thiserror
允许使用#[derive(Error)]
为自定义错误类型派生Error
trait。
- 核心概念: 本章介绍了
第十八章:文件操作
- 核心概念: 本章介绍了如何在 Rust 中进行文件操作,包括创建、打开、写入和读取文件。
- 文件操作:
std::fs::File
用于表示文件,可以使用File::create()
创建新文件,File::open()
打开现有文件,write_all()
写入字节数据,read_to_string()
读取文件内容。 OpenOptions
:OpenOptions
结构体用于自定义文件操作的行为,如只创建文件,不覆盖已有文件。
第十九章:异步编程
- 核心概念: 本章介绍了 Rust 的异步编程,使用了
tokio
crate。 - 异步编程: 使用
async
关键字声明异步函数,使用.await
等待异步操作完成。#[tokio::main]
用于标记异步的 main 函数。可以使用tokio::try_join!
来等待多个异步任务完成,并在其中任何一个任务失败时返回错误。
- 核心概念: 本章介绍了 Rust 的异步编程,使用了
第二十章:操作符重载和其他类型
- 核心概念: 本章介绍了 Rust 的操作符重载、关联类型和
bool
类型。 - 操作符重载: 通过实现
std::ops
中的 trait 可以实现操作符重载,例如Add
、Sub
、Mul
和Div
。 - 关联类型和关联常量: Trait 可以包含关联类型和常量,使用
const
定义常量。 - bool 类型: Rust 的
bool
类型只有true
和false
两个值。
- 核心概念: 本章介绍了 Rust 的操作符重载、关联类型和
第二十一章:继续探索
- 核心概念: 本章介绍了 Rust 标准库中的一些其他重要功能,包括 panic hook 和 backtrace。
- Panic Hook: 可以使用
std::panic::set_hook
设置自定义的 panic hook,在程序 panic 时执行。 - Backtrace: Backtrace 用于追踪程序调用栈,可以帮助调试错误。
unreachable!
宏:unreachable!
宏用于标记永远不会被执行的代码。
第二十二章:编写自定义宏
- 核心概念: 本章介绍了如何编写自定义宏,用于代码生成。
- 宏: 可以使用
macro_rules!
定义宏。宏可以使用ident
、expr
和tt
等类型匹配不同的输入。 - 宏的重复: 使用
$(...)
和*
或+
可以匹配零个或多个、一个或多个重复的标记。?
用于表示零个或一个重复。 - 标准库宏:
format_args!
宏 用于格式化字符串,todo!
宏用于标记未实现的代码。dbg!
宏用于调试打印。matches!
宏用于匹配表达式和模式。
第二十三章:终端时钟和秒表
- 核心概念: 本章展示了如何使用 Rust 构建一个终端时钟和秒表程序。
- Ratatui: 本章使用了
ratatui
crate 来构建终端界面。 - 程序结构: 秒表应该具有三种状态:未启动、运行和停止。
第二十四章:Web 服务
- 核心概念: 本章介绍了如何构建一个简单的 Web 应用程序。
- Axum: 本章使用了
Axum
crate 来构建 Web 服务。 - 静态变量: 提到了如何使用
Arc<Mutex>
来在多线程环境中使用静态变量,但没有深入展开。
总结来说,这本书从 Rust 的基础语法开始,逐步深入到更高级的概念,如所有权、生命周期、泛型、闭包、多线程、宏和外部 crate 等,并通过实际例子展示了如何使用 Rust 构建各种应用程序。