起步:安装、Hello World 与 Cargo — 第 1 章拆解
起步:安装、Hello World 与 Cargo
这一章讲三件事: 怎么把 Rust 装上;不借助任何工具手写一个程序并编译运行; 以及为什么真实项目一律用 Cargo 来管。读完你会拿到全书反复用到的那套基本动作—— 后面每一章的项目都是从
cargo new开始的。不需要任何基础。
1. 先看全景:这一章走完,你的电脑上会有什么
主线例子就一件事:把一个 Hello, world! 程序从白纸做到能交出去。
全章围绕它走两条路,对比着走:
路线 A(手写) 路线 B(Cargo)
───────────────── ──────────────────────────────
手写 main.rs cargo new hello_cargo(脚手架自动建好)
rustc main.rs cargo build → 产物在 target/debug/
./main cargo run(改代码后自动重编译再跑)
cargo check(只查不编,最快)
cargo build --release(开优化,慢编译换快运行)
图说:同一份代码,路线 A 是一条命令走到底,路线 B 是一组约定。
两条路的终点一样;区别在代码一多,路线 A 就管不动了。这一章在全书链条里的位置:它不给任何"语言机制",只给你工作台。 书特意把话说在前面——"绝大多数 Rust 项目都用 Cargo,本书其余部分假定你也用"1。 所以别把这一章当可跳过的安装指南:它立的那些约定(src 目录、Cargo.toml、target 目录)第 2 章起每一步都在用。
2. 装环境:rustup 管 Rust 的版本
Rust 通过一个叫 rustup 的命令行工具来安装,它管的是"Rust 的版本和配套工具", 而不是只装一次就完事。装完可以用一条命令验证:
$ rustc --version
rustc x.y.z (abcabcabc yyyy-mm-dd)能看到版本号、提交哈希、提交日期三样,就说明装好了2。以后升级只需要 rustup update,
卸载是 rustup self uninstall,本地文档 rustup doc 离线就能翻。
这里只解释一个后面会反复出现的词。
编译器(compiler)是把人写的源代码翻译成机器能直接执行的文件的程序。
rustc 就是 Rust 的编译器,你写的 .rs 文件经它之手变成可执行文件。
在这一行它是个普通角色,但它的脾气贯穿全书:它不光翻译,还挑错——
而且挑得比多数语言的编译器狠得多(第 4 章起你会一直被它拦)。
两个安装细节值得知道,都是"踩坑时才想起"型的:
- 还需要一个链接器(linker,把编译产物拼成一个可执行文件的程序)。 一般系统自带;报链接错误就装个 C 编译器,它通常附赠链接器, 而且有些常用 Rust 包本身就依赖 C 代码3。
- Windows 上安装器会提示装 Visual Studio,为的就是链接器和原生库4。
3. 手写 Hello World:最小的一个 Rust 程序长什么样
跳过 Cargo,先徒手做一遍。约定:Rust 源文件以 .rs 结尾,文件名多个单词用下划线连(hello_world.rs)5。
fn main() {
println!("Hello, world!");
}编译运行:
$ rustc main.rs
$ ./main
Hello, world!rustc main.rs 之后,目录里多出一个可执行文件(Windows 上是 main.exe 外加一个 .pdb 调试信息文件)6。逐行看这三行代码能学到三个本书从头用到尾的细节:
fn main()是程序的入口。 每个可执行的 Rust 程序,运行时第一个执行的函数就叫main;括号里没有参数 (参数就是调用时传给函数的值),不返回东西。函数体用大括号{}包住, 左大括号约定跟在函数声明同一行。println!后面那个感叹号表示:这是宏(macro),不是普通函数。 如果它是普通函数,就写作println(没有!)。宏是"写代码来生成代码"的那套办法,第 20 章才展开;现在只要记住:见到名字带!的,就是在调宏,宏不总守函数的规矩7。- 行尾的分号表示这个式子到此为止。
Rust 代码大多数行以
;结尾,后面讲语句与表达式时会再回来(第 3 章)。
一个对动态语言用户要紧的对比
如果你用 Ruby、Python、JavaScript 这类语言长大,可能不习惯"编译"和"运行"是两个分开的步骤。书里点明了 Rust 的取舍:Rust 是预先编译(ahead-of-time compiled)的语言——编译出可执行文件后,交给别人,别人机器上没装 Rust 也能跑;而 .rb、.py、.js 文件交出去,对方得先装对应的运行环境8。原书把话挑明:"语言设计里处处是权衡。"
这句"处处是权衡"不是客套,是这本书的暗线。你每学一个 Rust 特性,都可以问一句:它拿什么东西换了什么。这一章的权衡是:多一步编译,换一个能独立分发、不依赖对方环境的可执行文件。
4. Cargo:这一章真正的主角
4.1 Cargo 是什么、为什么人人都用它
Cargo 是 Rust 的构建系统兼包管理器9。三个词拆开:
| 词 | 意思 | Cargo 替你做的事 |
|---|---|---|
| 构建系统 | 把源代码变成可执行文件的那套流程 | 调编译器、传参数、决定先编哪个后编哪个 |
| 包管理器 | 管"别人的代码"的工具 | 下载你声明依赖的库,并把那些库也编译好 |
书里的口径很直接:代码一复杂,要管的可选项和依赖一多,"让 Cargo 来协调构建就省事得多"10。
它管的那种"别人的代码"在 Rust 里有个专门名字:crate——这是 Rust 对代码包/库的称呼,
Cargo.toml 里的 [dependencies] 段就是列 crate 的地方。这个词现在记住,第 7、14 章会把它彻底讲透。
4.2 cargo new:一个项目骨架里有什么
$ cargo new hello_cargo
$ cd hello_cargo这一条命令建出一个目录,里面有两样东西一个文件夹:Cargo.toml、src/main.rs,外加帮你初始化的 Git 仓库(在已有 Git 仓库里运行则不会)11。目录布局本身就是一条约定:
hello_cargo/
├── Cargo.toml ← 项目的"户口本":名字、版本、用哪版 Rust、依赖谁
├── src/
│ └── main.rs ← 代码只住在这里
└── target/ ← cargo build 之后出现:编译产物全在这(以后)顶层目录只放 README、许可证、配置文件这些"与代码无关"的东西;源码一律进 src。
书里的原话是"每样东西都有它的位置,每样东西都在它的位置上"——这条约定让任何人拿到一个 Cargo 项目都知道往哪看12。
Cargo.toml 的内容(这就是 cargo new 生成的原样):
[package]
name = "hello_cargo"
version = "0.1.0"
edition = "2024"
[dependencies]- 文件格式是 TOML,一种刻意做得"一看就懂"的配置格式。
[package]开头的一段在声明:这是个包,名字叫hello_cargo,版本0.1.0。edition = "2024"指定这个项目按 Rust 2024 版(edition,约每三年发一版)的语法和习惯来编译——这个键的含义附录 E 专讲,现在只需知道:它存在,而且新项目的默认值就是 202413。[dependencies]是空段:这个项目谁也不依赖。第 2 章马上往里填第一个外部 crate。
4.3 build / run / check:三个命令各干什么
主线例子从空项目走到第一次 cargo run,书里有完整的真实输出,一步一步看:
第 ① 步:cargo build(第一次)
$ cargo build
Compiling hello_cargo v0.1.0 (file:///projects/hello_cargo)
Finished dev [unoptimized + debuginfo] target(s) in 2.85 secs产物不在当前目录,而在 target/debug/hello_cargo。注意 dev 与 unoptimized 字样:默认编出来的是调试版——不做优化、编译快、跑得慢,专为"改十遍跑一遍"的循环设计14。
第 ② 步:cargo run(没改代码时)
$ cargo run
Finished dev [unoptimized + debuginfo] target(s) in 0.0 secs
Running `target/debug/hello_cargo`
Hello, world!关键在 in 0.0 secs:Cargo 发现文件没动过,跳过编译直接跑。
如果你刚改过源代码,同样的命令会先出现 Compiling ... 那一行再跑15。
所以日常流程是 cargo run 一把梭,不用记 build 之后那一长串路径。
第 ③ 步:cargo check(只查不编)
$ cargo check
Checking hello_cargo v0.1.0 (file:///projects/hello_cargo)
Finished dev [unoptimized + debuginfo] target(s) in 0.32 secscheck 只验证"代码能不能编译过",不产出可执行文件。为什么有人要这个?因为跳过生成可执行文件那一步,它比 build 快得多——写代码的过程中隔几分钟查一次"还编得过吗",用 check;真要跑程序时才 build 或 run16。
第 ④ 步:cargo build --release
$ cargo build --release
Compiling hello_cargo v0.1.0 (file:///projects/hello_cargo)
Finished release [optimized] target(s) in 2.85 secs产物落在 target/release/。开优化的版本编译慢、跑得快——所以书里特意叮嘱:量程序跑得有多快时,一定要编 release 版再量,拿 debug 版测出来的数字不是这个程序的真实速度17。
第 ⑤ 步:Cargo.lock 悄悄出现
第一次 cargo build 后项目顶层还会多一个 Cargo.lock。它记录这个项目依赖的确切版本,不需要你手动改,Cargo 全权管理18。项目没有依赖时这个文件近乎空壳,第 2 章加了外部 crate 之后它就变得要紧了。
4.4 回头看:两条路线的分水岭
现在回到第 1 节那张对照图。手写的 rustc main.rs 和 Cargo 到底差在哪?
差的不在"能不能编出同一个程序"——在"项目长大之后谁还管得动"。 一个文件、零依赖,两者等价;一旦变成十几个文件、依赖三五个外部库, "下载哪些版本、按什么顺序编译、参数怎么传"全变成手工活,这就是 Cargo 存在的理由19。 另外 Cargo 的命令在所有操作系统上长得一样——这也是书从这里起不再区分 Linux/macOS/Windows 写法的原因20。
5. 作者的判断与证据
这一章基本没有需要辩护的主张,只有两处态度值得标出来:
- "绝大多数 Rust 项目都用 Cargo"——这是社区事实陈述,证据是它成了全书的默认前提1。
- "设计里处处是权衡"——编译/运行分两步换可分发可执行文件,这是作者主动点破的语言设计观,后面所有章节都能见到这个视角8。
判断(我们的,不是书里的): 这一章教的最有价值的东西其实不是命令,而是目录约定即接口。
src/放代码、Cargo.toml写元数据、target/装产物——约定一旦统一,任何工具、任何 CI、 任何新队友都能零成本接手一个陌生项目。Rust 生态后来的强协作性,第一层地基就浇在这里。 如果错,会错在: 约定人人遵守靠的是工具默认生成 + 社区共识,若有大批项目偏离默认布局, 这条"统一接口"的论断就要打折——但就本书成书时的生态现状看,偏离者寥寥。
6. 边界与局限
- 版本敏感:安装命令、IDE 集成指引这类内容随时间失效最快。本拆解依据的是 2026-10 收录的第三版文本,实际安装请以官网为准。
- 这一章不教任何语言机制——变量、类型、函数一概没有。那是第 3 章的活;想先看完整的"写程序"流程,第 2 章的猜数字游戏一章看完再回来补课也行(这是原书自己给的路径建议)。
Cargo.toml的全部能力(profiles、feature、workspace……)这里只露一角,第 14 章专讲。
7. 可带走的
- 装 Rust 用 rustup;
rustc --version验证;rustup update升级。 - 任何 Rust 可执行程序都从
fn main()开始;名字!是宏,名字是函数。 - Rust 预先编译:产物是可以直接分发、对方无需装环境的可执行文件。
- 新项目一律
cargo new;源码进src/,Cargo.toml是项目的户口本。 - 日常三命令:
cargo run(边改边跑)、cargo check(最快地知道还编不编得过)、cargo build --release(要性能时)。 - debug 版快编译慢运行,release 版反过来;测性能必须测 release 版。
Cargo.lock记依赖的确切版本,别手改,交给 Cargo。edition = "2024"指定按 2024 版语言习惯编译,新项目默认值(附录 E 讲机制)。
8. 原文地图
| 主题 | 原书章 | 原文位置 |
|---|---|---|
| rustup 安装与验证 | Chapter 1: Getting Started | text/08-ch01-chapter-1-getting-started.txt:19(搜「latest stable version」) · text/08-ch01-chapter-1-getting-started.txt:74(搜「rustc --version」) |
| Hello World 程序解剖 | 同上 | text/08-ch01-chapter-1-getting-started.txt:194(搜「Anatomy of a Rust Program」) |
| 宏与感叹号 | 同上 | text/08-ch01-chapter-1-getting-started.txt:223(搜「Rust macro」) |
| 预先编译语言 | 同上 | text/08-ch01-chapter-1-getting-started.txt:272(搜「ahead-of-time compiled language」) |
| Cargo 是什么 | 同上 | text/08-ch01-chapter-1-getting-started.txt:284(搜「build system and package manager」) |
| Cargo.toml 逐行 | 同上 | text/08-ch01-chapter-1-getting-started.txt:329(搜「Open Cargo.toml」) |
| build / run / check 对比 | 同上 | text/08-ch01-chapter-1-getting-started.txt:377(搜「cargo build」) · text/08-ch01-chapter-1-getting-started.txt:418(搜「cargo check」) |
| release 构建与基准测试告诫 | 同上 | text/08-ch01-chapter-1-getting-started.txt:447(搜「cargo build --release」) |
Footnotes
-
出处:「Chapter 1: Getting Started」第 294 段(
text/08-ch01-chapter-1-getting-started.txt:294,搜「vast majority of Rust projects」)。原话:绝大多数 Rust 项目都用 Cargo,本书其余部分假定读者也用。 ↩ ↩2 -
出处:「Chapter 1: Getting Started」第 74 段(
text/08-ch01-chapter-1-getting-started.txt:74,搜「rustc --version」)。 ↩ -
出处:「Chapter 1: Getting Started」第 49 段(
text/08-ch01-chapter-1-getting-started.txt:49,搜「You will also need a linker」)。 ↩ -
出处:「Chapter 1: Getting Started」第 64 段(
text/08-ch01-chapter-1-getting-started.txt:64,搜「prompted to install Visual Studio」)。 ↩ -
出处:「Chapter 1: Getting Started」第 161 段(
text/08-ch01-chapter-1-getting-started.txt:161,搜「always end with」)。 ↩ -
出处:「Chapter 1: Getting Started」第 245 段(
text/08-ch01-chapter-1-getting-started.txt:245,搜「outputs a binary executable」)。 ↩ -
出处:「Chapter 1: Getting Started」第 223 段(
text/08-ch01-chapter-1-getting-started.txt:223,搜「calls a Rust macro」)。 ↩ -
出处:「Chapter 1: Getting Started」第 272 段(
text/08-ch01-chapter-1-getting-started.txt:272,搜「ahead-of-time compiled language」)。结尾的"处处是权衡"见同段(text/08-ch01-chapter-1-getting-started.txt:277,搜「Everything is a trade-off」)。 ↩ ↩2 -
出处:「Chapter 1: Getting Started」第 284 段(
text/08-ch01-chapter-1-getting-started.txt:284,搜「build system and package manager」)。 ↩ -
出处:「Chapter 1: Getting Started」第 460 段(
text/08-ch01-chapter-1-getting-started.txt:460,搜「much easier to let Cargo coordinate the build」)。 ↩ -
出处:「Chapter 1: Getting Started」第 319 段(
text/08-ch01-chapter-1-getting-started.txt:319,搜「two files and one directory」)与第 321 段(text/08-ch01-chapter-1-getting-started.txt:321,搜「initialized a new Git repository」)。 ↩ -
出处:「Chapter 1: Getting Started」第 362 段(
text/08-ch01-chapter-1-getting-started.txt:362,搜「inside the src directory」)。 ↩ -
出处:「Chapter 1: Getting Started」第 334 段(
text/08-ch01-chapter-1-getting-started.txt:334,搜「edition =」)。edition 键的说明见第 347 段(text/08-ch01-chapter-1-getting-started.txt:347,搜「Appendix E」)。 ↩ -
出处:「Chapter 1: Getting Started」第 380 段(
text/08-ch01-chapter-1-getting-started.txt:380,搜「creates an executable file in target/debug」)。 ↩ -
出处:「Chapter 1: Getting Started」第 407 段(
text/08-ch01-chapter-1-getting-started.txt:407,搜「hadn’t changed」)。 ↩ -
出处:「Chapter 1: Getting Started」第 427 段(
text/08-ch01-chapter-1-getting-started.txt:427,搜「skips the step of producing an executable」)。 ↩ -
出处:「Chapter 1: Getting Started」第 447 段(
text/08-ch01-chapter-1-getting-started.txt:447,搜「cargo build --release」)与第 454 段(text/08-ch01-chapter-1-getting-started.txt:454,搜「benchmarking your code」)。 ↩ -
出处:「Chapter 1: Getting Started」第 390 段(
text/08-ch01-chapter-1-getting-started.txt:390,搜「keeps track of the exact versions」)。 ↩ -
出处:「Chapter 1: Getting Started」第 460 段(
text/08-ch01-chapter-1-getting-started.txt:460,搜「programs grow to multiple files」)。 ↩ -
出处:「Chapter 1: Getting Started」第 442 段(
text/08-ch01-chapter-1-getting-started.txt:442,搜「same no matter which operating system」)。 ↩