Rust 教程
写给已经会一门带 GC 的语言(Java / Go / JavaScript / C# / Python)、 第一次认真学 Rust 的人。不从「什么是变量」讲起,也不按语法元素 平均分配篇幅 —— 这类读者会卡住的地方只有一个:代码看着没问题,编译器就是不让过。所以所有权那一章占了全书最大的篇幅,而基础语法压成一篇。
章节顺序就是阅读顺序,从头读最省事。 全部示例都是能单独编译的完整程序,每次构建前由npm run test:rust 用真的 rustc 跑一遍 —— 「这段编译不过、报的是 E0382」这种话,在这里是被验证过的断言,不是印象。
按错误码查
被编译器拦下来的时候,你手上唯一确定的东西就是那个E0xxx。下面每一条都对应一个跑得出这个错误码的完整示例。
| 错误码 | 这条示例在演示什么 | 出处 |
|---|---|---|
E0038 | `dyn` 的代价:不是所有 trait 都能做成 trait 对象 | 泛型、trait 与 dyn |
E0106 | 借用不能比被借的东西活得久 | 借用:& 与 &mut 的两条规则 |
E0106 | 结构体里存引用,就得带上标注 | 生命周期标注到底在说什么 |
E0117 | 孤儿规则:别人的类型 + 别人的 trait = 不行 | 泛型、trait 与 dyn |
E0277 | 🚨 `Rc` 过不了线程边界,`Arc` 可以 | 并发与 Send / Sync |
E0277 | `?` 只能用在返回 `Result` 的函数里 —— `main` 也可以是 | Result 与 ?:没有异常怎么活 |
E0277 | 字符串不能用数字下标 | 切片:借用一段,而不是整个 |
E0282 | 同样是「推不出来」,报的码可能不一样 | 语法速通:给已经会编程的人 |
E0308 | 🚨 唯一非用 `dyn` 不可的场合:一个容器装多种类型 | 泛型、trait 与 dyn |
E0308 | 不同宽度的整数不会自动转换 | 为什么是 Rust:既没有 GC,也不用手动 free |
E0369 | `assert_eq!` 要求类型能比较、能打印 | 测试与 cargo test |
E0381 | 没初始化就用,是编译错误不是垃圾值 | 为什么是 Rust:既没有 GC,也不用手动 free |
E0382 | 赋值就是移动:原变量当场失效 | 移动:赋值为什么会让变量失效 |
E0382 | 函数传参也是一次移动 | 移动:赋值为什么会让变量失效 |
E0382 | 部分移动:拿走一个字段,整体就不完整了 | 移动:赋值为什么会让变量失效 |
E0499 | 规则二:可变借用同时只能有一个 | 借用:& 与 &mut 的两条规则 |
E0502 | 真实形状:边遍历边往里加 | 借用:& 与 &mut 的两条规则 |
E0502 | 规则二的另一半:可变借用不能和不可变借用共存 | 借用:& 与 &mut 的两条规则 |
E0502 | 切片是借用,所以它会挡住对原串的修改 | 切片:借用一段,而不是整个 |
E0507 | 从容器里「拿」一个出来,拿不走 | 移动:赋值为什么会让变量失效 |
E0596 | 🚨 `Rc` 里的东西改不了 —— 除非套一层 `RefCell` | 智能指针与内部可变性 |
E0597 | 🚨 标注不延长任何东西 | 生命周期标注到底在说什么 |
E0599 | 类型逼着你处理「没有」 | Option:没有 null 怎么活 |
E0624 | 🚨 别用 `.len()` 试 —— 你会撞到一个误导性的报错 | Option:没有 null 怎么活 |
章节
起步:先把地基和你会的那门语言对齐 · 4 篇不讲「什么是变量」—— 只讲 Rust 和你已经会的那门语言在哪里不一样所有权:编译器为什么拒绝我 · 5 篇全书最重的一章。移动、借用、生命周期 —— 所有「代码看着没问题却编译不过」都在这里用类型表达:没有 null,也没有异常 · 5 篇enum 与模式匹配、Option 与 Result、泛型与 trait —— Rust 让你在类型里说清楚的那些事工程:把代码组织起来 · 3 篇模块与 crate、测试、集合与字符串 —— 从「能编译」到「能维护」进阶:绕开借用检查器的正当手段 · 3 篇智能指针与内部可变性、迭代器与闭包、并发 —— 前面学的规则在这里被合法地放宽