Rust 入门
1.安装 Rust 工具链(rustup)
rustup.rs - The Rust toolchain installer
下载 rustup-init.exe
打开 rustup-init.exe
1 | Rust Visual C++ prerequisites |
1.使用VS,用MSVC编译链;2.手动安装必备组件;3.不装,用GNU编译链
选了1
1 | Welcome to Rust! |
1.标准安装;2.自定义安装;3.退出安装
1 | >1 |
2.检查安装
打开一个新的终端:
1 | # 检查 rust 编译器 版本 |
3.配置镜像源
在 %USERPROFILE%\.cargo\ 位置 创建 config.toml(自定义 cargo配置),配置国内镜像源
1 | [source.crates-io] |
4.编辑器相关配置
使用VSCode
安装扩展:
rust-analyzer:官方语言服务器,提供代码补全、跳转、重构等核心功能
CodeLLDB:调试器,支持 Rust 的原生调试
Even Better TOML:TOML 配置文件语法高亮和补全
Error Lens:实时显示错误和警告
GitLens:Git 集成工具
5.创建第一个项目
1 | # 使用 cargo 创建新项目 |

6.开始正式学习
🏁 第一关:数据基石 —— 内存模型设计
首先,请在本地编辑器中打开 src/main.rs。请清空该文件中的所有内容,我们从零开始。
在这一关里,你需要亲手定义我们的待办事项数据类型。
📚 核心知识点预热
- struct(结构体):用于将相关联的数据打包在一起。
- String 与 &str 的所有权:在结构体中存储文本时,通常使用拥有自主所有权的 String 类型,而不是只读借用的 &str(生命周期太短),这能避免复杂的生命周期标记。
- impl(实现块):在 Rust 中,数据和行为是分离的。我们通过 impl 为特定的 struct 编写方法。
- self 的秘密:
- 关联函数(没有 self):如 fn new() -> Self,类似于静态方法,用于创建实例。
- 实例方法(带 self):
- &self:不可变借用,只能读取数据(如 list 方法)。
- &mut self:可变借用,可以修改内部数据(如 add 方法)。
🏁 第一关后半段:列出待办事项 (list)
我们需要让 TodoList 拥有“列出所有待办”的能力。
📚 核心知识点预热:
- *不可变借用 (&self)*:
- 上一关的 add 方法修改了列表,所以用的是 &mut self(可变借用)。
- 这一关的 list 方法只需要读取并展示数据,不修改任何内容,所以使用 &self(不可变借用)即可。
- iter() 与 enumerate():
- self.items.iter() 获取数组的迭代器,避免夺走 items 元素的所有权。
- .enumerate() 类似于 Python 中的 enumerate,能同时为我们提供序号 (从 0 开始的 index) 和当前项的引用。
- 三元表达式的替代者:
- Rust 没有 ? : 三元表达式,因为 Rust 的 if 本身就是可以返回值的表达式!
- 例如:let status = if item.completed { “[✓]” } else { “[ ]” };
🏁 第二关:听懂我们的命令 (解析参数)
📚 核心知识点预热:
- std::env::args():这是 Rust 标准库提供的一个函数,用来获取我们在命令行输入的所有参数。
- collect():把这些参数收集到一个动态数组 Vec 中,方便我们使用。
- 参数的顺序:
- 比如你输入 cargo run – add “学习”。
- args[0] 是程序自己的名字(我们可以忽略它)。
- args[1] 是动作,也就是 “add”。
- args[2] 是具体的任务内容,也就是 “学习”。
🏁 第二关后半段:用 match 控制命令分发
📚 核心知识点预热:
- match(模式匹配):
- Rust 里的 match 极其严格,它要求你必须考虑到所有可能的情况(完备性)。
- 例如,如果用户输入了我们不认识的命令,我们必须有一个保底的 _ => { … } 分支来捕获它们,否则编译器会直接报错!
- as_str():
- command 是一个 String 类型,我们通过 .as_str() 或者直接匹配切片将其转换为字符串切片(&str),这样能更方便地匹配字面量(如 “add”、”list”)。
🏁 第 3 关:记忆永恒 —— JSON 序列化与文件读写
📚 核心知识点预热:
- #[derive(Serialize, Deserialize)] 宏:
- 只要在结构体上方写上这一行,Rust 就会自动为它生成序列化(转换成 JSON 字符串)和反序列化(从 JSON 字符串读取回来)的代码!
- Result<T, E>:
- Rust 里的很多操作(比如读取文件、解析 JSON)可能会失败。它们不直接返回结果,而是返回一个 Result。
- Result 是一个枚举,有两部分:
- Ok(data):操作成功,里面装着我们想要的数据。
- Err(error):操作失败,里面装着报错信息。
- ? 传播符:
- 如果一个操作返回的是 Result,我们可以在它后面加一个 ?。
- 它的意思是:“如果成功,就取出里面的值继续走;如果失败,程序直接从当前函数返回,并把这个报错传递给调用者”。这让我们的代码变得极其干净!
如何读懂 Rust 的报错结构
一个标准的 Rust 编译报错通常由以下几部分组成:
1.error[EXXXX]:红色的错误编号。你可以把这个 EXXXX(例如 E0433)复制到搜索引擎中,或者在终端运行 rustc –explain EXXXX,Rust 会给你配图和文字讲解这个错误的原理。
2.–> src\main.rs:12:1:精确的错误位置。文件名、行号、列号。
3.| 符号与代码片段:编译器贴心地把你写错的代码贴在终端里。
4.^ 符号或波浪线:在出错的那几个具体字符下方精准画线。
5.help: 或 note::这是 Rust 的精髓!编译器经常会直接给出“正确答案”,告诉你“是不是应该这样写…”。
声明第三方库
Cargo.toml 里声明的第三方库
🏁 第 4 关:完美防御 —— 完成与删除功能设计
我们的 Todo CLI 已经能“添加”和“列出”任务了。现在,我们要让它更完整:支持“标记完成” (done) 和“删除” (remove)。
📚 核心知识点预热:
- 数组越界的灾难(Index Out of Bounds):
- 如果你的列表里有 2 个任务,用户输入了 cargo run – done 5。如果你不做检查,Rust 会直接引发 panic(程序崩溃),这在生产环境是灾难性的。
- 我们的代码需要非常健壮。我们需要做边界检查:输入的序号不能为 0,也不能大于当前任务列表的长度。
- Result<T, E> 的自定义报错:
- 我们可以让方法返回一个 Result<(), &’static str>。
- 如果序号正确,返回 Ok(())。
- 如果序号超出范围,返回 Err(“错误:序号超出范围!”),然后在 main 函数里把这个友好的错误打印给用户,而不是崩溃。
- 动态数组的操作:
- 标记完成:self.items[index - 1].completed = true;
- 删除元素:self.items.remove(index - 1);
- 思考:为什么是 index - 1?因为我们列表展示给用户的是从 1 开始的自然数,但在计算机中,数组索引是从 0 开始的
把保底的 _ => 分支,永远放在 match 的最底部!
src/main.rs - 主程序
cargo.toml - 项目名称、版本、依赖
打包(编译成可独立运行的发布版本)
1 | # (在项目目录中) 以发布模式打包 |
默认情况下是在 调试模式下 cargo run 或 cargo build
而当你加上 –release 参数时,编译器会切换到发布模式(Release Mode):
- 全力优化:编译器会花更多时间去优化你的代码(例如循环展开、内联函数、消除未使用的代码等),这会让 Rust 程序的运行速度提升几倍到几十倍!
- 去除调试信息:剥离多余的调试符号,大幅缩减可执行文件的体积。
- 输出路径:编译生成的可执行文件会存放在 target/release/ 目录下。
打包生成:\target\release\xxx.exe (是一个完全独立的二进制文件)