cargo run -- -h
- vscode 插件: Rust Syntax、Dependi、rust-analyzer
- rust-analyzer: 可变变量会带有下划线
- Rust 官网 有中文很方便
- Rust Playground 在线直接写代码并运行,不用自己准备环境,没有任何自动提示,非常适合入门学习
- Rustup 文档:The rustup book
- Cargo 文档:The Cargo Book
- 学习过程中关闭 AI 提示,仅保留语言自带的关键字、函数提示
- vscode 只在当前项目关闭某扩展:扩展 - 指定扩展 - ⚙️ - 禁用(工作区)
- Rust 编译过程中的报错多个同出、信息丰富、推荐准确、格式友好,多去尝试出错对学习很有帮助
- 结构体定义和实例化的语法基本一致
- 整体结构都是名称 + 大括号: 定义时前面多一个
struct
声明 - 属性声明都用冒号: 定义时用冒号声明类型,实例化时用冒号声明具体的值
- 不同属性之间都是用逗号连接
- 整体结构都是名称 + 大括号: 定义时前面多一个
- Rust: 我要学习的这门语言
- Rustup: Rust 安装器和版本管理工具
- Cargo: Rust 的构建工具和包管理器(对一个 Rust 项目来说的)
在 macOS、Linux 上安装,直接运行官网的这个命令
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
如果报错没有权限写入 .bash_profile
,就先把 .bash_profile
文件的所有者改为当前用户,然后就可以正常安装了
sudo chown $(whoami) ~/.bash_profile
stackoverflow: Could not write to .bash_profile when installing Rust on macOS Sierra
安装之后计算机上就有 Rustup、Rust 编译器和 Cargo 了。一般说 Rust 的版本指的就是其编译器的版本,编译器决定了写出 Rust 语法的功能。
# Rustup 这个工具的版本
$ rustup --version
rustup 1.28.2 (e4f3ad6f8 2025-04-28)
info: This is the version for the rustup toolchain manager, not the rustc compiler.
info: The currently active `rustc` version is `rustc 1.88.0 (6b00bc388 2025-06-23)`
# Rust 编译器的版本
$ rustc --version
rustc 1.88.0 (6b00bc388 2025-06-23)
# Cargo 这个工具的版本
$ cargo --version
cargo 1.88.0 (873a06493 2025-05-10)
Rust 每六周发布一次稳定版,用 rustup update
可以更新 Rustup 自身、编译器、Cargo 这些工具为最新稳定版。Rustup 文档:The rustup book
Cargo: Rust 的构建工具和包管理器。文档:The Cargo Book
cargo init
初始化项目cargo init xxx
可以创建并初始化项目
cargo run
自动构建项目并运行- 可以使用
cargo run --bin foo
的方法运行单独尝试的代码:有时我想临时试验一个代码,可以创建一个src/bin/foo.rs
文件,然后运行cargo run --bin foo
即可 - 所有
--
前的参数都会传给 Cargo,--
后的代码会传给我写的程序- 例如
cargo run -- -h
就是我的程序的帮助文档 - 而
cargo run -h
是cargo run
的帮助文档
- 例如
- 可以使用
cargo test
自动构建项目并运行测试cargo add
添加项目依赖cargo --version
查看版本
宏(macro)是编译时展开(类似代码模板替换),没有函数调用开销,而且可以自定义语法结构
宏的使用格式就是 名称!
,比函数调用多一个感叹号
另:Rust 中无法用函数实现可变参数
println
中的 ln
是 "line" 的缩写,明确表达 "打印并换行"(print line)的意图,所有平台一致,都会自动在输出结尾会自动追加一个换行符 \n
/U+000A
,没有回车符 \r
/U+000D
println
示例
println!(); // prints just a newline
println!("hello there!");
println!("format {} arguments", "some");
let local_variable = "some";
println!("format {local_variable} arguments");
println!("format {value} arguments", value="some");
println!("{:#?}", (100, 200)) // (
// 100,
// 200,
// )
完整的格式化规则见 std::fmt
阶段 | 动作 |
---|---|
词法 | 切成 token |
语法 | 生成带 macro_call!() 节点的 AST |
宏展开 | 递归扫描 AST,把宏节点替换为新的 AST 节点;仍含宏则继续,深度 ≤ 128 |
声明宏 | 模式匹配 + 片段替换 |
过程宏 | 运行 proc-macro crate,返回 TokenStream 再解析 |
结果 | 纯 AST,无宏节点;随后进入语义分析 |
let val = "val";
println!("{}", std::any::type_name_of_val(&val)); // &str
只能给人读
- 行注释、行尾注释
//
- 块注释、token 中间注释
/* ... */
可以被 rustdoc 读取
- 文档行注释
///
- 文档块注释
/** ... */
- 模块级文档
//!
- 模块级块文档
/*! ... */
- What are the differences between Rust's
String
andstr
? - Stack Overflow - When should I use String vs &str?
&str
的数据是 &[u8]
格式,切片时是对 u8
的切片,因此切片位置如果不在 UTF-8 的合法边界会报错
-
Cargo.toml
人类可读的项目清单:用于描述项目依赖项,由开发者编写,使用cargo
初始化项目或管理三方库的时候也会自动更新 -
Cargo.lock
Cargo 自动生成的确定性快照:包含有关依赖项的准确信息。由 Cargo 自动维护,不应该被手动编辑。只有当项目是应用时才需要提交Cargo.lock
,库项目不需要
Cargo 在 2010–2014 年首创 “manifest + lockfile” 模式,后来成为 Python(Poetry、uv)、Node、Go 等生态的模板。
TOML 为 Tom’s Obvious, Minimal Language,2013 年由 Tom Preston-Werner 独立提出,非 Rust 社区发明,仅被 Cargo 采用为配置格式
格式化工具 rustfmt
功能 | Option | Result<T, E> |
---|---|---|
构造 | Some(v) / None |
Ok(v) / Err(e) |
判断 | is_some() / is_none() |
is_ok() / is_err() |
变换 | map , and_then |
map , map_err , and_then |
传播 | let x = opt?; |
let x = res?; |
匹配 | match o { Some(v) => _, None => _ } |
match r { Ok(v) => _, Err(e) => _ } |
// Option 变换
let opt = Some(10);
let doubled = opt.map(|x| x * 2); // Some(20)
let chained = doubled.and_then(|x| Some(x + 3)); // Some(23)
// Result 变换
let res: Result<i32, &str> = Ok(10);
let doubled = res.map(|x| x * 2); // Ok(20)
let chained = doubled.and_then(|x| Ok(x + 3)); // Ok(23)
let error_msg = res.map_err(|_| "mapped err"); // Ok(10)
快速取值
-
unwrap
直接取出内部值;遇到 None 或 Err 会 panic!let x = Some(1).unwrap(); // 1 let y: i32 = None.unwrap(); // panic!
-
expect(message)
作用同 unwrap,但 panic 时可打印自定义信息let x = Some(1).expect("empty"); // 1 let y = None.expect("empty"); // panic!("empty")
-
unwrap_or(default)
成功/有值时取值,否则返回给定默认值,永不 paniclet x = None.unwrap_or(0); // 0
-
unwrap_or_else(closure)
成功/有值时取值,否则运行闭包产生默认值,永不 paniclet x = None.unwrap_or_else(|| 0); // 0 let y = Err("!").unwrap_or_else(|_| -1); // -1
- 匹配多种值、模式(含 struct/tuple/enum/切片/范围/字面量)
- 匹配时同时进行变量绑定与解构
- 穷尽检查:必须覆盖所有可能,可用
_
兜底 - 可以作为表达式:每个分支返回统一类型的值
- 守卫:
if 条件
在匹配成功后追加额外布尔限制 - 绑定模式:
@
把匹配成功的整体值再绑定到一个名字
- 再过一遍教程,看看有什么新的理解和问题
- 教程里缺少了 create_todo 的改动过程
- 再完整看下代码有没有什么不理解的