从「Rust 凭什么写 Web」到跑通第一个 Web 服务¶
这一章讲两件事: 第一,Rust 这门常被和「系统编程」「底层」放在一起说的语言, 到底凭什么能写网站——书里给了八条理由、七条短板,每条都带了证据,不是口号; 第二,一个完全没装过 Rust 的人,怎样一步步把第一个能在浏览器里打开的 Rust 程序跑起来。 读完你会拿到全书的「地基论断」(Rust 适合干这个,以及工具链长什么样), 后面十三章全部盖在这块地基上。不需要任何 Rust 基础。
1. 这一章在全书链条里的位置¶
先交代两个词:客户端(发请求的那一端,比如浏览器)与服务器(应答的那一端,后文反复出现)。
这本书的写法是:从头到尾用一个「工单管理系统」(ticket——可以理解成公司里大家提交和流转 任务单的那个系统)当主线项目,一章一章把它造完整。但在动工之前,必须先回答一个更靠前的问题:
为什么造它用的是 Rust,而不是大家默认的 Python、Java、Go 或 JavaScript?
这一章就是那个「开工前论证」。它分两半:前半是「语言评估」——Rust 适合 Web 的八条理由、 七条短板;后半是「环境搭建」——把 Rust 的工具链装起来,跑通一个最小的 Web 程序。 作者在这一章明确说了全书的立场:不假装 Rust 是银弹,而是把它的强项用起来、把缺口补上1。
2. 顶层全景:这章的论证结构¶
上半:语言评估
历史(Web 怎么一路走到今天)
→ Rust 与 Web 的渊源(一个坏电梯 → 浏览器引擎 Servo → 2015 年发布)
→ 八条「适合」的理由(模块化 / 性能 / 安全 / 并发 / 高级特性 / 网络 / 框架 / Playground)
→ 七条「不适合」的短板(规格变动 / 库易弃 / 安全可绕过 / 学习陡 / 偏底层 /
缺全家桶框架 / 没有官方 REPL)
下半:环境搭建
rustup(装工具链)→ Cargo(建项目、管依赖、跑程序)
→ rustfmt(自动排版)→ 第一个 Axum Web 服务(浏览器里看到 Hello World)
→ IDE(编辑器怎么选)
主线例子(全章共用):一个叫 hello 的最小 Web 服务。
从 cargo new hello 开始,到浏览器里看到 <h1>Hello, World!</h1> 结束,
中间每一步都有具体的命令、文件内容、端口号和版本号。后面每讲一个工具,都回到这个例子上走一步。
3. 先看历史:Web 是怎么变成今天这个样子的¶
这一节解释一个背景问题:为什么「写网站」这件事,会从一个写静态页面的活儿, 变成一门需要认真选语言、选架构的工程学科。 知道了来路,才能明白后面所有选择的理由。
书里的历史线是这样走的2:
最早的网页是死的。 一段文字放在某台机器的硬盘上,谁请求就原样发回去。 很快人们不满足了:同一个地址,不同的访客、不同的时间,应该看到不同的内容。 于是 Web 服务器学会了一件事:把收到的请求转交给另一个程序,由那个程序现场生成回答。 各家服务器做法不一样,后来人们把这件事定了统一规矩,叫 CGI(通用网关接口)。 从此「写脚本处理请求」成了标配,Perl、Python、Ruby、PHP 这类脚本语言借这股东风 变成了 Web 的主力——写脚本舒服,而且 CGI 也不挑语言3。
另一边,浏览器里也想跑程序。 这个需求造出了 JavaScript, 也造出了 Java 小程序(Java applet)这类嵌在页面里跑的东西。
然后是 Web 2.0,转折点在这里。 人们不再满足于「网站上嵌几个小应用」, 而是要把一切——博客、社交、相册、视频——都搬进浏览器,而且要求体验连贯。 Flash、Silverlight 衰落,JavaScript 上位;服务器那边的逻辑越来越复杂, 把重量往客户端(浏览器)挪就越来越划算4。
网站越来越大,就又出了新问题。 给企业做的大应用天然长成「一块巨石」: 功能越多越难维护。于是架构师们学会了「把大象切成好管理的小块」—— 这就是今天微服务、前后端分离这一切做法的源头。书里强调了一句很要紧的话: 这个复杂度一旦上去就回不来了——人总是把越来越复杂的任务交给计算机, 一头想做得更多,一头想做得更省力5。
这一节还埋了全书的一个判定:Web 开发的复杂化是不可逆的,所以「选型的论证」 「架构的视角」这些看似务虚的内容,在本书里占了整整两章——第 2 章马上讲。
4. Rust 与 Web 的渊源:一个坏电梯引来的一门语言¶
这一节回答:Rust 这门语言是从哪来的,它从诞生第一天起跟 Web 是什么关系。
书里给的来历非常具体:Rust 最初的动机,是给底层语言加上一张安全网。 导火索是一个坏掉的电梯——用没有安全防护的底层语言写的电梯控制程序出了错, 有人受了伤(补充:这个广为流传的故事指的是 1999 年朝鲜阳爆炸电梯事故, 书里只提了「一部坏电梯」,细节不在书里,来自通用知识)。 这个「给高效但危险的底层语言加约束」的想法,在 Mozilla 那里得到了第一个大用场: 写下一代浏览器引擎 Servo。Rust 第一个稳定版发布于 2015 年6。
更有意思的是后面这个细节:仅仅一年之后,2016 年,就有人建了一个网站, 名字起得极其诚实,叫 arewewebyet.org——「我们到底能不能用 Rust 写 Web 了?」—— 专门跟踪用 Rust 做 Web 开发的成熟度。书里说,这个网站 2016 年的快照 (用 Wayback Machine 存的)说明了一件事:「用 Rust 写 Web」这个想法,几乎和这门语言一样老7。
到写这本书的时候(2026 年版),那个网站的答案已经从早期的「还不行」 变成了「Yes!And it is freaking fast!」——可以了,而且快得吓人8。
判断(我们的,不是书里的): 「are we X yet」这个网站本身就是生态成熟度的晴雨表—— 一门新语言早期最缺的不是特性,而是「别人已经替你踩过坑」的证据。当社区开始自发建网站 回答「能不能拿它干活」时,说明已经有一批先行者在生产环境用它了。 如果错,会错在: 有些语言社区也会出于热情过早宣布「可以了」, 所以「网站说可以」只能当初步信号,真正的判据仍然是第 2 章那种逐组件的评估。
5. 八条理由:Rust 凭什么适合写 Web¶
这一节是全书论证的主梁之一。 作者先立了一条规矩:没有完美的语言, 任何语言都是一堆设计取舍的指纹,有些领域被照顾得好,有些就差—— 我们的工作不是找银弹,而是掂量「被照顾好的领域」跟我们要干的活对不对得上9。 在这个口径下,书里列了八条 Rust 适合 Web 的理由。我们逐条讲透。
5.1 模块化:语言之外的「货」够不够全¶
写 Web 不是光写代码,而是不断回答「这个轮子有没有人造好了」。
书里给的判据很朴素:一门语言靠生态活着——可复用的库、打包、版本管理、 搜索、下载、文档浏览。这些东西的集散地叫 registry(包仓库,Rust 的叫 crates.io)。 Rust 这方面已经是现成的:有自己的构建工具、依赖管理,包仓库也在正常运转10。
对 Web 开发,这意味着:HTTP 服务器、数据库驱动、JSON 处理这些通用件, 大多不需要自己造。
5.2 性能:编译型语言对脚本型语言的「碾压级」证据¶
这一条书里没有空喊「Rust 快」,而是给了一个有出处的对照实验。
故事从一个具体的痛点说起。 作者回忆当年用 LAMP 那套 (Linux + Apache + MySQL + PHP/Perl/Python)堆页面,压加载时间到 3 秒以下; 后来做一个订餐网站,每天午饭点流量准时打顶,而「网站快不快」根本没法一句话回答—— 第一次来的访客还是老用户?有多少家餐厅开着?有没有套餐时段? 性能是一个多因子的问题,单说「慢」没有意义11。
然后是关键证据。 为了搞清「框架和库在性能等式里占多大分量」, 一个叫 TechEmpower 的机构组织了一系列 Web 框架基准测试。早期一次的结果颇为惊人:
编译型语言比解释型语言快得多,事件驱动的异步模型更是鹤立鸡群。 编译型(Java)对脚本型(PHP)的优势到了 40 倍——书里的原话是, 这个结果对脚本语言的拥护者来说是「devastating」(毁灭性)的, 这个量级「再也无法轻易 dismiss 掉」12。
这个基准后来又重复了 22 轮,Rust 常年位居前列;到写书时(第 23 轮), Rust 框架在综合榜前 10 名里占了 4 席,比任何其他语言都多,还包揽了前三名13。
这条推理链值得记住: 不是「Rust 很快所以用它」,而是「基准测试证明语言类型 (编译 vs 解释)和并发模型(异步事件驱动 vs 一线程一请求)对性能的影响是数量级的」, Rust 恰好两者都占。
5.3 安全:不用垃圾回收的内存安全¶
这是 Rust 的立身之本,书里讲得很直白。
要解决的问题: 传统底层语言(C/C++)有几类臭名昭著的崩溃性 bug—— 书里点了五类的名:段错误(segmentation fault)、缓冲区溢出(buffer overrun)、 悬空指针(dangling pointer)、重复释放(double-free)、释放后使用(use-after-free)。 它们共同的特点是:让程序里的变量处于一种自相矛盾的状态, 崩溃来得莫名其妙,排查极难14。
别人怎么解,代价是什么: 高级语言(Python、Java)把内存管理藏进抽象后面, 程序员不需要懂栈和堆的区别——代价是要加一层专门的清理机制, 就是大家听到的引用计数和垃圾回收(garbage collector,简称 GC)。 GC 会拖性能,所以系统编程语言一直不愿意用它15。
Rust 的做法: 换一个思路——不GC,而是在编译期就不让你写出那种自相矛盾的代码。 编译器直接拒绝把变量留在不一致状态;语法层面也不再帮你隐瞒栈、堆、作用域这些现实, 但报错发生在编译期而不是运行期——「这次它是在编译时提醒你,而不是运行时崩给你看」, 这是质的飞跃16。
对 Web 开发的直接意义:服务端程序要长期运行、处理不可信的输入, 内存类漏洞是整个行业安全事故的大头;这类 bug 在 Rust 里是「编译不过」, 不是「上线后被利用」。
5.4 并发:把数据竞争变成编译期错误¶
先解释词。 并发(concurrency)是多件事「同时进行」; 书里特意区分了两个常被混用的概念:在多核 CPU 上,并行(parallel) 是同一时刻真的在多核上跑;多任务(multitasking)是在核不够时, 把任务切成碎片 clever 地来回切换,看起来像同时进行17。
问题在哪: 多核普及后,语言却还背着单核时代的包袱。更麻烦的是 数据竞争(data race)——两个任务同时读写一个变量,结果取决于谁先到, 这种错极难复现、极难排查,以前只能靠程序员手动小心翼翼地防。
Rust 的做法: 编译期检查直接给出保证——编译出来的代码不可能踩进数据竞争, 因为它根本不允许变量被这样共享、被同时写18。在此之上,异步编程(async)这套 抽象也已经是现成的:它用状态机跟踪每个任务,底层只用少数几个重量级线程, CPU 和内存开销都小——对服务器和数据库通信这种海量连接场景,这正是最优形态19。
对 Web 的意义:一个网站服务器同时挂着成千上万个连接,并发是它的日常; 「并发错误在编译期被消掉」等于把这整类线上事故从根上拔了。
5.5 高级特性: borrowed 来的高层招式¶
Rust 是多范式语言,借了很多语言的长处——书里点了 Ruby、OCaml、Haskell 的名。 程序员能用泛型、函数式编程的招式,还有一个简化版的面向对象模型 (基于 trait,可以先理解成「接口」)20。
书里还有一个观察值得记住:特性集合太大对人是有麻痹作用的——学不完,就不敢下手。 Rust 刻意给特性踩刹车,把已有特性做扎实,而不是堆新特性。 Web 开发要的高级特性(并发、泛型、函数式、async)它都有,而且是有意裁剪过的版本。
5.6 网络支持:现成的轮子密度¶
写 Web 离不开网络编程。书里给了一个当时(写书时)的数字:crates.io 上 「Network programming」分类下已经有 2765 个包,从高层 HTTP 到低层 TCP 都有21。
值得一提的引子:连 Rust 官方教程(《The Rust Programming Language》,行话叫 "the Rust book") 都专门有一章带你从零实现一个多线程服务器——但在真实项目里不需要自己造, 轮子密度足够,选就是了。后文 Axum、Tokio 就是这条路上的选择。
5.7 框架:不止一个能打的,而且前端也能用 Rust 写¶
Rust 已有经过生产环境考验的 Web 框架,也有一批有潜力的新框架; 书里预告:后面会「在框架版图上转一圈,比较主要候选,然后为我们的项目选一个」 (那就是第 2、3 章的活)22。
这条里最重磅的是后半句:借助 WebAssembly,可以用 Rust 写前端, 在易用性和性能上跟 JavaScript 框架同台竞争——一门语言同时写后端和前端, 这是这本书后面所有前端演示的地基(第 3、4 章的 Yew 就是它)。
5.8 Playground:不用建项目的即席试代码¶
Rust Playground(play.rust-lang.org)是一个网页编辑器(沙箱 = 只能在里面跑、碰不到你机器的隔离环境): 把代码丢进去立刻运行,不用建项目、不用建文件,还预置了常用 crate。 工作中经常需要「快速试一下某个特性成不成立」,它专门服务这个场景23。
6. 七条短板:作者没回避的那一面¶
这一节同样重要——它是「评估」而不是「布道」的另一半。 书里列了七条,每条我们讲清「问题是什么、书里给的缓解是什么」。
6.1 规格爱变(早期尤其 notorious)¶
Rust 早期以「善变」出名:特性随版本来去,采用者要么不敢依赖,要么不停地跟着重构。 书里引了 2014 年 Rust 两位核心开发者 Aaron Turon 和 Niko Matsakis 一句自嘲:
「从 Rust 的早期算起,你只靠得住两件事:安全,和变化。而且有时候连第一个都靠不住。」24
缓解: 后来引入了 release channels(发布渠道)和 editions(版次)机制, 保证 crate 之间的互操作,稳定性问题在语言层面基本解决。 但注意书里接下来的话:生态里的 crate 还拖着这个不稳定的尾巴——这就引到第二条25。
6.2 库容易半途而废¶
crates.io 上大量项目短命、没人用。连知名框架也逃不出:Rocket 开发放缓, 社区一度解读为「死了」;Actix(另一个流行框架)作者曾宣布退出,上了新闻26。
书里给的结论很冷静:早期的东西必然变,「唯一不变的是变化」,做好在 Rust 生态里 应对变更的心理准备——这也是第 14 章(收尾)会回来讲的维护话题的伏笔。
6.3 安全特性是可以被绕过的¶
这是书里最有技术含量的一条短板。Rust 没法做到「整体安全」,原因和 Haskell 当年 面对的困境同构:语言本身再纯,一要和外部世界打交道, purity 就保不住了—— 外部函数大概率是 C/C++ 写的,按 Rust 的标准就是 unsafe(不安全)的,内存方面没有任何保证。 Kenny Kir(Rust for Windows 的作者,Kenny Kerr)一句话点破: 「这里的一切都将是不安全的」27。
更要命的是:既然语言必须提供「放弃安全检查」的逃生门(unsafe 块),
就没有什么能拦住开发者滥用这扇门。甚至连 Result 这种「优雅的错误容器」
都能被一句 unwrap 绕过——里面没值时它会直接触发 panic!(让程序当场崩掉)28。
这条短板的正确读法: Rust 给的是「默认安全、可以 escape」,而不是「绝对安全」。 团队纪律(什么时候允许 unsafe、unwrap 用在哪)和语言本身一样重要。
6.4 学习曲线陡¶
新概念(所有权、借用检查)需要专门学习;除了概念,还有一堆「无理由的偏好式风格」
——书里举的例子:函数声明用 fn 这个短缩写,而不是 function 或 Kotlin 的 fun。
作者的评价很公允:单个看都是小事,学习成本是这所有小事加起来的总和;
好语言要在「顺应程序员直觉」和「为关键概念引入新东西」之间找平衡29。
书里还有个让人会心一笑的细节:新手注定会和编译器「吵」上一阵子, 直到传说中那个「豁然开朗」的时刻到来——这几乎是每个 Rust 学习者的共同体验30。
6.5 偏底层:不替你藏住机器¶
书里引了一句 Go 程序员的名言式态度:「我不在乎我的结构体在堆上还是栈上。」 ——这正是高级语言用户的普遍心态:把实现细节抽象掉,我专心写业务逻辑。 Rust 反着来:它用编译期检查逼你面对计算机体系结构的现实, 栈、堆、作用域、生命周期,一个都藏不住,还在上面加了所有权和借用31。
对来自 Python/JS 的 Web 开发者,这是真实的心理门槛;书里也不讳言: 这可能是某些人的 deal breaker(一票否决项)。
6.6 缺「全家桶式」框架¶
先解释词。 书里区分了两类框架:微框架(micro-framework)只解决「按统一方式 收发请求」这一件事,轻、灵活;而约定优于配置(convention over configuration) 的全家桶框架,连认证、路由、表单、模板全都替你装好,零配置开箱即用。
Rust 几乎只有前者(Sinatra/Flask 的同辈)。微框架的好处是按量付费、灵活; 坏处是常见任务都得自己攒——而快速开发需要「伸手就有」32。 这直接决定了这本书后面大量章节的存在:第 7 章的访问控制、第 8 章的通知, 在很多语言里是框架自带的,在 Rust 里要自己动手或用专门 crate 拼。
6.7 没有官方的 REPL¶
先解释词。 REPL = Read-Eval-Print Loop,读入一行代码 → 求值 → 打印结果,循环——
就是编程语言的命令行界面,随手丢几行代码试效果,连编译这一步都帮你藏起来了,
甚至能配合 shebang(脚本第一行那个 #!)把编译型语言当脚本用33。
Rust 至今没有官方 REPL(有几个社区项目在做,比如 evcxr,但未官方支持)。 对习惯了 Python/Node 交互式探索的开发者,这是个真实的不便; 缓解就是 5.8 那个 Playground——功能有重叠,但约束更多(安全沙箱、不能访问本机环境)。
7. 环境搭建:从装工具到浏览器里的 Hello World¶
这一节是全章主线例子的主战场。 我们跟着书走完全程, 每一步的命令和文件内容都是原书给的(版本号是写书时的,今天会更新,机制不变)。
第 ① 步:rustup——装工具链¶
Rust 用 rustup 管理开发环境。它的正式定义是个 fancy 名字:toolchain multiplexer (工具链多路复用器)——「一套能帮你轻松切换编译器的机制」。 工具链(toolchain)= 编译器 rustc 加上相关工具(Cargo、文档工具等); 目标(target)= 你编译出来的程序要在哪个平台上跑。交叉编译(在一个平台上编译 给另一个平台跑的程序)后面编译 WebAssembly 时会用到34。
rustup 管三样东西:
| 概念 | 是什么 |
|---|---|
| channel(渠道) | 发布线:stable(稳定,生产用)、beta(下一个 release 的候选)、nightly(开发快照,最新特性) |
| component(组件) | 可单独加装的工具,比如代码格式化工具 rustfmt |
| profile(配置档) | 一组搭配好能用的组件;默认档就够,不用手调 |
装好后 rustup show 会报告当前工具链。书里当时的输出是:
stable-x86_64-unknown-linux-gnu,rustc 1.68.235。
切换的真实演示(注意这两段具体的版本号):
~/Projects/rust ❯ rustup default nightly # 把默认切到 nightly
~/Projects/rust/test-nightly ❯ rustc -V
rustc 1.70.0-nightly (700938c07 2023-04-04) # 进了子目录,nightly
~/Projects/rust/test-nightly ❯ cd ..
~/Projects/rust ❯ rustc -V
rustc 1.68.2 (9eb3afe9e 2023-03-27) # 出了目录,stable
图说:同一台机器上 stable 与 nightly 并存;rustup override set nightly
让某个目录及其子目录固定用 nightly,出了目录就回到默认。
(版本号是原书当时的;你跑会更新,机制一模一样。)
这个「按目录覆盖」(rustup override set nightly)很实用:想尝鲜 nightly 特性的实验项目
放在单独目录里,不污染别的项目36。
第 ② 步:Cargo——建项目、管依赖、跑程序¶
cargo new hello 一行建出一个项目,结构就三样:
hello/
├── Cargo.toml ← 项目的户口本:名字、版本、依赖清单
└── src/
└── main.rs ← 程序本体
图说:Cargo.toml 用 TOML 格式(一种刻意做简单的配置格式)书写。
书里在依赖清单里加了两行——这两个名字就是全书后端的两大主力,先眼熟:
[dependencies]
axum = { version = "0.6.12" } # Web 框架:管路由、请求、响应
tokio = { version = "1.0", features = ["full"] } # 异步运行时:真正驱动并发的那台引擎
然后是三个最常用命令,差别要分清:
| 命令 | 干什么 | 快/慢 |
|---|---|---|
cargo check |
检查代码有没有错,只编译不生成可执行文件 | 快,写代码时反复跑 |
cargo build |
完整编译出可执行文件 | 慢一些;有些错误只在 build 阶段才报 |
cargo run |
build 完接着运行 | 日常跑程序用这个 |
cargo check 和 cargo build 的结果会缓存复用:先 check 再 build,
依赖不会被重复下载编译,build 只是在 check 的基础上补上「生成代码」这一步37。
Cargo 的命令远不止这三个(new/init/add/remove/test/bench/update/
search/publish/install/doc/clean),书里给了一张完整清单38。
后面章节会用到的:cargo add(加依赖)、cargo test(跑测试,第 6 章)、
cargo install(装命令行工具,第 8 章装 MailHog 替代品时会用到类似机制)。
第 ③ 步:把 hello 变成 Web 服务(Axum 初登场)¶
把 src/main.rs 换成下面这段(原书代码,逐行解释):
use axum::{response::Html, routing::get, Router};
use std::net::SocketAddr;
#[tokio::main]
async fn main() {
let app = Router::new().route("/", get(handler)); // 路由表:路径 "/" → 处理函数 handler
let addr = SocketAddr::from(([127, 0, 0, 1], 3000)); // 监听地址:本机 + 端口 3000
println!("listening on {}", addr);
axum::Server::bind(&addr).serve(app.into_make_service()).await.unwrap();
}
async fn handler() -> Html<&'static str> {
Html("<h1>Hello, World!</h1>") // 响应体:一段 HTML
}
逐行说清三件新东西:
#[tokio::main]:Rust 的异步函数不能自己跑起来,需要一个异步运行时来驱动; 这个注解就是把main交给 Tokio 托管——Tokio 就是那个「用状态机管理任务、 只用少量线程」的引擎(5.4 节讲的抽象,落地成它)。Router和route("/", get(handler)):路由表。意思是「收到对/的 GET 请求, 就调用handler函数」。这是所有 Web 框架的通用骨架,Axum 的写法只是其中一种 flavor。Html<&'static str>:响应类型,告诉 Axum「这是一段 HTML,原样放进响应体」。
cargo run 之后,命令行停在 listening on 127.0.0.1:3000 不再返回——
因为程序现在是一个服务器,活着等你敲门。浏览器打开 http://localhost:3000/,
看到加粗大字号的 Hello, World!,第一个 Rust Web 服务就通了。Ctrl + C 停掉39。
判断(我们的,不是书里的): 注意这一节的「比例感」——一个能响应浏览器的 Rust 服务,核心就 10 行代码 + 两个依赖。Rust 写 Web 的门槛不在「起步」, 而在「做大之后的纪律」(类型、错误处理、生命周期),这正是第 4 章以后的内容。 如果错,会错在: 如果项目需要大量现成的全家桶能力(后台管理、ORM 迁移、权限), Rust 侧的实际起步成本会比这 10 行高得多——书里第 3 到 10 章就是在付这笔成本。
第 ④ 步:rustfmt——让代码长一个样¶
rustfmt src/main.rs --edition 2021 会把文件重排成社区统一的代码风格
(缩进、换行、链式调用怎么折行)。上面那段代码 rustfmt 之后,
axum::Server::bind(&addr).serve(...).await.unwrap() 被折成了 4 行40。
为什么要这一步?不是为了好看:统一格式让「读别人的代码」和「读自己的旧代码」 成本一致,而 Web 开发是团队协作,读远多于写。rustfmt 就是前面组件清单里的默认组件之一。
第 ⑤ 步:IDE——编辑器怎么选¶
命令行够认识工具,日常开发还是 IDE 舒服。书里给了三条路,都成熟:
| 选择 | 说明 |
|---|---|
| JetBrains IntelliJ / RustRover | 装 Rust 插件;商业版和社区版(免费)都有 |
| VS Code | 免费;装 Rust 扩展元包,一次带来 rust-analyzer(语言服务器)、crates(依赖管理辅助)、语法高亮三个扩展 |
| 其他编辑器(Neovim、Emacs、Sublime…) | 都行——因为 Rust 实现了 LSP(Language Server Protocol,语言服务器协议) |
解释 LSP: 这是一套编辑器与「语言智能」之间的标准协议。语言服务器负责 「懂代码」(补全、跳转定义、看文档、改错),编辑器只要会说这套协议就能接上。 所以「编辑器怎么选」在 Rust 这里不是关键问题——关键能力被抽出来放在了所有编辑器 都能共享的地方。这也解释了为什么 VS Code 生态对它几乎是零成本接入41。
8. 作者的判断与证据(分开标)¶
书里给了证据的:
- 编译型 vs 解释型的性能差距可达 40 倍(TechEmpower 基准,有机构、有轮次、有截图)12;
- Rust 框架在 TechEmpower 第 23 轮综合前 10 占 4 席、包揽前三13;
- crates.io 网络编程分类 2765 个包(写书时的数字)21;
- Rocket 放缓、Actix 作者退出,都有公开新闻出处26。
作者自己的评估(证据弱一档,是行业经验式的):
- 「和编译器吵架直到豁然开朗」是学习曲线的真实形态——这是经验之谈,不是测量;
- 「crate 易弃」除两个有名案例外,主要是 crates.io 上的观感;
- 八条七条的清单本身,就是作者的取舍框架,换一位作者清单会不一样。
9. 边界与局限¶
- 版本会过时: 书中所有具体版本(rustc 1.68.2、axum 0.6.12、tokio 1.0)是 2023–2026 年间写书时的快照; 机制(rustup/Cargo/组件/channel)稳定,数字别照搬。原书自己也提醒:读到时版本多半已更新, 「为避免意外,保持书上版本也行」42。
- 性能论据依赖特定基准: TechEmpower 测的是框架「裸性能」,真实网站的性能瓶颈 往往在外部(数据库、网络、业务复杂度)——书里自己在 5.2 开头就承认了这一点11。
- 「are we web yet」只是信号灯: 见第 4 节判断块。
- 本章不教 Rust 语法: 所有权、借用、生命周期这些语言核心,全书都「在用到处讲」, 系统教学不在本书范围(notCovered 之一)。
10. 可带走的¶
主线例子一行走完: cargo new hello → Cargo.toml 加 axum 和 tokio →
main.rs 写 10 行(路由 / → handler 返回 HTML)→ cargo run →
命令行停在 listening on 127.0.0.1:3000 → 浏览器打开 localhost:3000 看到
Hello, World! → Ctrl + C 结束。中间版本号(1.68.2 / 0.6.12)是原书快照,机制不变。
- Rust 进 Web 的理由不是「快」一个字,而是一条链: 安全(编译期消掉内存 bug) → 并发(数据竞争编译期消掉)→ 异步(状态机 + 少量线程,为高并发场景而生) → 性能(编译型 + 异步,基准测试里对脚本型是数量级优势)→ 生态(crates.io 轮子密度)。
- 没有银弹: 七条短板(规格变动史、库易弃、unsafe 可绕过、学习陡、偏底层、 缺全家桶、无官方 REPL)每一条都是真实成本;选 Rust 是买它的强项、认它的代价。
- 「安全」的确切含义: 不是「写不出错的程序」,是「一整类内存错误变成编译不过」; 但 unsafe 逃生门存在,纪律决定实际安全性。
- 工具链四个名字记牢: rustup(装/切工具链,按目录 override 很实用)、 Cargo(建项目、管依赖、跑程序)、rustfmt(统一排版)、Clippy(代码体检,后面章节接入 CI)。
- Cargo 三命令的分工: check(快,查错)→ build(生成可执行)→ run(编译+运行); 结果互相缓存。
- 一个 Axum 服务的最小骨架:
#[tokio::main](Tokio 驱动异步)+Router(路由表)+route(path, get(handler))+Server::bind(addr).serve(...)。 换任何框架,这套骨架都在。 - Rust 前端的地基是 WebAssembly: 一门语言写前后端两端——这是全书后面 Yew(第 3、4 章)的存在理由。
- 编辑器不是关键,LSP 才是: 任何支持 LSP 的编辑器都有补全、跳转、文档。
11. 原文地图¶
| 主题 | 原书章 | 原文位置 |
|---|---|---|
| 全书范围假设(不教 HTML/HTTP/微服务) | Beginning with Rust(第 1 章 Introduction) | text/08-fm-introduction.txt:20(搜「usual suspects」) |
| Web 历史:静态页 → CGI → 脚本语言 | Beginning with Rust | text/08-fm-introduction.txt:55(搜「Common Gateway Interface」) |
| Web 2.0 与客户端增重 | Beginning with Rust | text/08-fm-introduction.txt:61(搜「Web 2.0」) |
| 复杂度不可逆、切分巨石 | Beginning with Rust | text/08-fm-introduction.txt:67(搜「sliced the elephant」) |
| 坏电梯、Servo、2015 发布 | Beginning with Rust | text/08-fm-introduction.txt:73(搜「broken elevator」) |
| arewewebyet 2016 快照 | Beginning with Rust | text/08-fm-introduction.txt:76(搜「Wayback Machine」) |
| 选型规矩:指纹与领域匹配 | Beginning with Rust | text/08-fm-introduction.txt:92(搜「fingerprint」) |
| 八条理由清单 | Beginning with Rust | text/08-fm-introduction.txt:92(搜「particularly well-suited」) |
| TechEmpower 40 倍差距 | Beginning with Rust | text/08-fm-introduction.txt:136(搜「40 times」) |
| 第 23 轮前 10 占 4 席 | Beginning with Rust | text/08-fm-introduction.txt:146(搜「top league」) |
| 五类内存 bug 清单 | Beginning with Rust | text/08-fm-introduction.txt:156(搜「Segmentation faults」) |
| 不用 GC、编译期警告 | Beginning with Rust | text/08-fm-introduction.txt:175(搜「garbage collection」) |
| 数据竞争不可能 | Beginning with Rust | text/08-fm-introduction.txt:181(搜「data races」) |
| 异步状态机、少量线程 | Beginning with Rust | text/08-fm-introduction.txt:184(搜「state machines」) |
| 2765 个网络包 | Beginning with Rust | text/08-fm-introduction.txt:199(搜「2765」) |
| 框架与 WebAssembly 前端 | Beginning with Rust | text/08-fm-introduction.txt:205(搜「battle-tested」) |
| Turon/Matsakis 自嘲引文 | Beginning with Rust | text/08-fm-introduction.txt:252(搜「safety, and change」) |
| editions 机制 | Beginning with Rust | text/08-fm-introduction.txt:258(搜「editions」) |
| Rocket/Actix 事件 | Beginning with Rust | text/08-fm-introduction.txt:267(搜「Rocket」) |
| Kenny Kerr「一切都将不安全」 | Beginning with Rust | text/08-fm-introduction.txt:279(搜「unsafe」) |
| unwrap 绕过 Result | Beginning with Rust | text/08-fm-introduction.txt:288(搜「unwrap」) |
| 与编译器吵架到顿悟 | Beginning with Rust | text/08-fm-introduction.txt:294(搜「argue with the compiler」) |
| 「不在乎堆还是栈」 | Beginning with Rust | text/08-fm-introduction.txt:309(搜「heap or stack」) |
| 微框架 vs 全家桶 | Beginning with Rust | text/08-fm-introduction.txt:337(搜「Sinatra」) |
| REPL 缺失与 shebang | Beginning with Rust | text/08-fm-introduction.txt:343(搜「read-eval-print」) |
| rustup、toolchain、channel | Beginning with Rust | text/08-fm-introduction.txt:364(搜「toolchain multiplexer」) |
| 交叉编译与 target | Beginning with Rust | text/08-fm-introduction.txt:367(搜「cross-compilation」) |
| 默认组件五件套 | Beginning with Rust | text/08-fm-introduction.txt:388(搜「Rust's build」) |
| nightly 切换与 override 演示 | Beginning with Rust | text/08-fm-introduction.txt:425(搜「default nightly」) |
| cargo new / Cargo.toml | Beginning with Rust | text/08-fm-introduction.txt:485(搜「cargo new」) |
| check 与 build 的缓存复用 | Beginning with Rust | text/08-fm-introduction.txt:545(搜「cargo check」) |
| Axum hello-world 代码 | Beginning with Rust | text/08-fm-introduction.txt:650(搜「Router::new」) |
| listening on 127.0.0.1:3000 | Beginning with Rust | text/08-fm-introduction.txt:746(搜「listening on」) |
| rustfmt 重排 | Beginning with Rust | text/08-fm-introduction.txt:674(搜「rustfmt」) |
| IDE 与 LSP | Beginning with Rust | text/08-fm-introduction.txt:765(搜「IntelliJ」)、text/08-fm-introduction.txt:801(搜「Language Server Protocol」) |
| 章节结论(不假装银弹) | Beginning with Rust | text/08-fm-introduction.txt:817(搜「silver bullet」) |
| Points to remember | Beginning with Rust | text/08-fm-introduction.txt:823(搜「Points to remember」) |
| Key terms(工具链/target/依赖) | Beginning with Rust | text/08-fm-introduction.txt:928(搜「Toolchain」) |
-
出处:「Beginning with Rust」(
text/08-fm-introduction.txt:817,搜「silver bullet」)。 ↩ -
出处:「Beginning with Rust」(
text/08-fm-introduction.txt:55,搜「Common Gateway Interface」)。 ↩ -
出处:「Beginning with Rust」(
text/08-fm-introduction.txt:55,搜「not picky」)。 ↩ -
出处:「Beginning with Rust」(
text/08-fm-introduction.txt:61,搜「Web 2.0」)。 ↩ -
出处:「Beginning with Rust」(
text/08-fm-introduction.txt:67,搜「sliced the elephant」)。 ↩ -
出处:「Beginning with Rust」(
text/08-fm-introduction.txt:73,搜「broken elevator」)。 ↩ -
出处:「Beginning with Rust」(
text/08-fm-introduction.txt:76,搜「Wayback Machine」)。 ↩ -
出处:「Beginning with Rust」(
text/08-fm-introduction.txt:146,搜「top league」)。 ↩ -
出处:「Beginning with Rust」(
text/08-fm-introduction.txt:92,搜「fingerprint」)。 ↩ -
出处:「Beginning with Rust」(
text/08-fm-introduction.txt:124,搜「registry」)。 ↩ -
出处:「Beginning with Rust」(
text/08-fm-introduction.txt:133,搜「lunchtime」)。 ↩↩ -
出处:「Beginning with Rust」(
text/08-fm-introduction.txt:136,搜「40 times」)。 ↩↩ -
出处:「Beginning with Rust」(
text/08-fm-introduction.txt:146,搜「top league」)。 ↩↩ -
出处:「Beginning with Rust」(
text/08-fm-introduction.txt:156,搜「Segmentation faults」)。 ↩ -
出处:「Beginning with Rust」(
text/08-fm-introduction.txt:172,搜「garbage collectors」)。 ↩ -
出处:「Beginning with Rust」(
text/08-fm-introduction.txt:175,搜「compile-time」)。 ↩ -
出处:「Beginning with Rust」(
text/08-fm-introduction.txt:181,搜「fragments」)。 ↩ -
出处:「Beginning with Rust」(
text/08-fm-introduction.txt:181,搜「data races」)。 ↩ -
出处:「Beginning with Rust」(
text/08-fm-introduction.txt:184,搜「state machines」)。 ↩ -
出处:「Beginning with Rust」(
text/08-fm-introduction.txt:190,搜「functional programming」)。 ↩ -
出处:「Beginning with Rust」(
text/08-fm-introduction.txt:199,搜「2765」)。 ↩↩ -
出处:「Beginning with Rust」(
text/08-fm-introduction.txt:205,搜「battle-tested」)。 ↩ -
出处:「Beginning with Rust」(
text/08-fm-introduction.txt:211,搜「Playground aims」)。 ↩ -
出处:「Beginning with Rust」(
text/08-fm-introduction.txt:252,搜「safety, and change」)。 ↩ -
出处:「Beginning with Rust」(
text/08-fm-introduction.txt:258,搜「editions」)。 ↩ -
出处:「Beginning with Rust」(
text/08-fm-introduction.txt:267,搜「Rocket」)。 ↩↩ -
出处:「Beginning with Rust」(
text/08-fm-introduction.txt:279,搜「unsafe」)。 ↩ -
出处:「Beginning with Rust」(
text/08-fm-introduction.txt:288,搜「unwrap」)。 ↩ -
出处:「Beginning with Rust」(
text/08-fm-introduction.txt:297,搜「preferential styling」)。 ↩ -
出处:「Beginning with Rust」(
text/08-fm-introduction.txt:294,搜「argue with the compiler」)。 ↩ -
出处:「Beginning with Rust」(
text/08-fm-introduction.txt:318,搜「stack, heap, scope, and lifetime」)。 ↩ -
出处:「Beginning with Rust」(
text/08-fm-introduction.txt:340,搜「reach for」)。 ↩ -
出处:「Beginning with Rust」(
text/08-fm-introduction.txt:343,搜「read-eval-print」)。 ↩ -
出处:「Beginning with Rust」(
text/08-fm-introduction.txt:367,搜「cross-compilation」)。 ↩ -
出处:「Beginning with Rust」(
text/08-fm-introduction.txt:419,搜「1.68.2」)。 ↩ -
出处:「Beginning with Rust」(
text/08-fm-introduction.txt:461,搜「override set nightly」)。 ↩ -
出处:「Beginning with Rust」(
text/08-fm-introduction.txt:545,搜「reuses」)。 ↩ -
出处:「Beginning with Rust」(
text/08-fm-introduction.txt:581,搜「Compile the current package」)。 ↩ -
出处:「Beginning with Rust」(
text/08-fm-introduction.txt:746,搜「listening on」)。 ↩ -
出处:「Beginning with Rust」(
text/08-fm-introduction.txt:704,搜「bind(&addr)」)。 ↩ -
出处:「Beginning with Rust」(
text/08-fm-introduction.txt:765,搜「IntelliJ」)、(text/08-fm-introduction.txt:801,搜「Language Server Protocol」)。 ↩ -
出处:「Beginning with Rust」(
text/08-fm-introduction.txt:817,搜「silver bullet」)。 ↩