跳转至

语言巡礼 — 三个小程序看懂 Rust 的用法与脾气

这一章讲三件事: Rust 的工具链长什么样;一个带测试、带命令行参数、带错误处理的小程序怎么从零跑起来; 以及怎么用第三方 crate 搭一个 web 服务。原书的立场也在这章亮明:Rust 没有单一「看家特性」, 它的全部设计服务于一个目标——安全的、高性能的系统编程1。 多线程那个程序留给下一章,本章是它的地基。

1. 顶层全景:从安装到三个程序

这一章的骨架是一张「造车流水线」式的流程图:

  rustup 装工具链(cargo / rustc / rustdoc)
      │  cargo new 建包(两个文件、九行样板)
      ▼
  程序一:命令行 gcd ── 函数、断言、单元测试、命令行参数
      │                顺手带出:trait、迭代器、Result、借用
      ▼
  程序二:Actix web 服务 ── 第三方 crate、async、闭包、derive 宏
      │
      ▼
  程序三:多线程曼德博画图(下一章)── 泛型、切片、scoped 线程

图说:每一步都建立在前一步的概念上,最后落到并发——那是 Rust 真正的卖点。

本章的主线例子就是程序一:命令行输入 42 56,输出 The greatest common divisor of [42, 56] is 14。 trait、迭代器、Result、借用这四个地基概念,都会在这一个程序上各走一步。

2. 工具链:cargo、rustc、rustdoc

装 Rust 的标准方式是 rustup(类比 Ruby 的 RVM、Node 的 NVM):新版本发布时敲一句 rustup update 就升级2。 装完你得到三个命令,书里给出了具体版本号,cargo 1.85.0、rustc 1.85.0(2025 年 2 月)3:

命令 干什么
cargo 编译管理 + 包管理 + 通用工具:建项目、构建、运行、管依赖
rustc Rust 编译器本体。平时由 cargo 代为调用
rustdoc 文档工具:把源码里特定形式的注释变成网页

cargo new hello 会建好一个包:一个 Cargo.toml(这个文件装的是元数据:包名、版本、edition——示例里是 edition = "2024") 和一个 src/main.rs,内容就是九行的 Hello World4。包(packages)在 Rust 里有个专门名字叫 crate ——不管库还是可执行文件都叫 crate;Cargo 和 crates.io 两个名字都是从这个词来的5。

cargo 的日常循环

建完包,日常就是三个命令转圈:cargo run 一键「编译 + 运行」,输出里能看到它先调 rustc、 再跑产物;cargo test 收集所有 #[test];cargo clean 删掉 target/ 里的全部生成物 (书里的实录:21 个文件、7.7 MB),删完再直接运行编译产物,操作系统报「没有那个文件」—— 干净得没有一丝残留29。

编译产物本身在 target/debug/ 下,可以直接执行;放那里是「带调试信息的开发版」。 第 2 章的曼德博程序会用到 cargo build --release——优化版,快得多。

3. 程序一:命令行 gcd

3.1 一个函数里的语法底色

原书用欧几里得算法求最大公约数,一个函数同时演示了半打语法决定:

fn gcd(mut n: u64, mut m: u64) -> u64 {
    assert!(n != 0 && m != 0);
    while m != 0 {
        if m < n {
            let t = m; m = n; n = t;
        }
        m = m % n;
    }
    n   // 没有分号:这个 n 就是返回值
}
  • fn 引入函数;参数类型必须写(n: u64 是 64 位无符号整数),返回值类型跟在 -> 后面; 但函数体内局部变量的类型不用写,Rust 会推断——let t = m; 里 t 自动是 u646。
  • mut(读作 mute,mutable 的缩写):默认变量初始化后不可改;要改就得在声明处明说。 书里说这反而是个阅读提示——带 mut 的变量接下来会被赋值7。
  • assert! 是宏(名字后的 ! 就是「这是宏」的标记):条件为假就让程序以一种叫 panic 的方式立即终止, 报错信息里带出错位置。和 C/C++ 不同,Rust 的断言永远检查,与编译方式无关; 想在 release 构建里跳过断言,有另一个宏 debug_assert!8。
  • 条件不加括号、大括号必填。if m < n { … }——rustc 甚至会为多余的括号发警告9。
  • 函数的值是最后那个不带分号的表达式。n 不带分号,所以它是返回值; return 只用于中途提前返回。更一般地,任何 { … } 块都是表达式,值是块里最后一个表达式的值——这个决定在第 5 章会展开成「表达式语言」。

3.2 单元测试就住在源码里

给 gcd 配测试,不用测试框架,直接在 main.rs 末尾加:

#[test]
fn test_gcd() {
    assert_eq!(gcd(14, 15), 1);
    assert_eq!(gcd(2 * 3 * 54321, 5 * 7 * 54321), 54321);
}

#[test] 是一个属性(attribute):给声明挂额外信息的开放机制(类比 C#/Java 的注解)。 它把 test_gcd 标记成测试函数——正常编译跳过它,cargo test 时自动收集、自动运行10。 测试可以散落在源码树各处、挨着被测代码放。

3.3 主线例子走一遍:cargo run 42 56

现在看完整的命令行程序,这是本章的主线例子:

use std::str::FromStr;
use std::env;

fn main() {
    let mut numbers = Vec::new();
    for arg in env::args().skip(1) {
        numbers.push(u64::from_str(&arg).expect("error parsing argument"));
    }
    if numbers.len() == 0 {
        eprintln!("Usage: gcd NUMBER ...");
        std::process::exit(1);
    }
    let mut d = numbers[0];
    for m in &numbers[1..] {
        d = gcd(d, *m);
    }
    println!("The greatest common divisor of {numbers:?} is {d}");
}

第一步:use 声明把名字引进来。 use std::str::FromStr; 引进一个叫 trait 的东西。trait 是一组方法的集合,类型可以实现它: 任何实现了 FromStr 的类型都有一个 from_str 方法,尝试从字符串解析(parse)出该类型的值11。 书里有句关键的话:就算代码里再没出现 FromStr 这个名字,trait 也必须在作用域内才能用它的方法——这个规矩以后会反复绊人。

第二步:Vec 与迭代器。 Vec::new() 建一个空向量;向量是可增长的数组(类比 C++ 的 std::vector、Python 的 list)。 类型 Vec<u64> 也不用写,Rust 从后面 push 进去的内容推断出来12。 env::args() 返回一个迭代器——按需逐个产生值、并知道什么时候完事的东西。 迭代器在 Rust 里无处不在(向量元素、文件的行、通道里的消息……),而且它有个承诺: 编译器通常能把 for 循环迭代器翻译成和手写的循环一样的机器码13。 迭代器还有一串方法可以直接用:.skip(1) 产生一个新迭代器,跳过头一个值—— 头一个值永远是程序自己的名字,所以要跳过。

第三步:Result——Rust 的错误没有异常。 u64::from_str(&arg) 不直接返回 u64,返回一个 Result,它是两种形态之一: | 形态 | 意思 | |---|---| | Ok(v) | 解析成功,v 是得到的值 | | Err(e) | 失败,e 是解释原因的值 |

凡是可能失败的事(输入输出、和操作系统打交道)都返回 Result。 原书在这里下了一个全书级别的判断:Rust 没有异常,所有错误要么走 Result,要么走 panic14。 .expect("…") 是 Result 的方法:是 Err 就打印消息并退出程序;是 Ok(v) 就取出 v 给你15。

第四步:那两个奇怪的符号——& 和 *。

for m in &numbers[1..] {     // & 干什么?
    d = gcd(d, *m);           // * 又干什么?
}

遍历的向量可能很大,Rust 不想在你不知情的情况下复制或消耗它——它要你声明「这堆内存归谁、活多久」。 &numbers[1..] 的意思是:借用从第二个元素开始的引用,向量的所有权仍归 numbers; m 挨个借用每个元素;*m 是解引用,取出它指向的那个 u64 交给 gcd16。 循环结束后 numbers 还拥有向量,Rust 在 main 结束时自动释放它。

这就是「借用」第一次出场。规则细节第 4 章讲,这里只需要记住:&x 借 x 的引用,*r 是引用 r 指向的值。

第五步:输出与退出码。 println! 是宏:模板字符串里的 {numbers:?} 被替换成变量的值,:? 表示按调试格式打印(带引号、转义)。 eprintln! 写到标准错误流。 退出码的约定和 C 相反:main 正常返回就算成功,想以错误退出必须显式调 std::process::exit(1) 或让 expect 失败17。

跑一次($ 是命令提示符,书里的输出实录):

$ cargo run 42 56
The greatest common divisor of [42, 56] is 14
$ cargo run
Usage: gcd NUMBER ...

3.4 这一段立住了四个地基概念

回到主线例子的角色分配:FromStr 代表 trait;env::args() 代表迭代器; expect 代表 Result 错误处理;&numbers[1..] 代表引用与借用。 这四个概念后面每一章都会用到,原书在第一章就全部埋下。

测试运行的实录

cargo test 的输出朴素而令人安心(书里的实录):一行「running 1 test」、 一行 test test_gcd ... ok、一行汇总「1 passed; 0 failed」。 测试函数就住在源码里、挨着被测代码,cargo test 自己把它们全找出来30。

4. 程序二:用第三方 crate 搭 web 服务

第二个程序还是那个 gcd,但用浏览器访问:页面让用户输入两个数,提交后服务器算结果。 这一节的主角不是程序本身,而是 crates.io——Rust 的免费开放包仓库, cargo add actix-web 一条命令就把第三方库登记进 Cargo.toml,下载、构建、更新全由 cargo 包办18。

4.1 依赖、版本与 feature

Cargo.toml 的 [dependencies] 段每行写一个 crate 名加版本号。两个细节值得带走:

  • 版本是「兼容范围内最新」:写 actix-web = "4.9.0",在新机器上构建或 cargo update 时, cargo 会取最新的兼容版本(比如 4.10.1)19。
  • crate 可以有可选 feature:serde 的 derive 功能(等下要用)不是默认开启的, 必须写 serde = { version = "…", features = ["derive"] } 显式申请20。

4.2 async:一个核伺候上千个连接

服务器长这样(骨架):

#[actix_web::main]
async fn main() {
    let server = HttpServer::new(|| {
        App::new()
            .route("/", web::get().to(get_index))
    });
    server.bind("127.0.0.1:3000").expect("…").run().await.expect("…");
}

两个新词。async fn,即异步(async)函数:等网络这种不耗 CPU 的时间可以让出来给别的任务, 一个 CPU 核就能灵敏地同时伺候上千个连接,不必为每个连接开一个系统线程。 它和 C#/JavaScript 的 async/await 同族21。机制细节(怎么实现的)书放在后面章节,本章只要会用。

闭包(closure):|| { App::new() … } 是一个可以像函数一样调用的值; 参数名写在两根竖线之间(这里没有参数)。Actix 为每个请求处理线程调用一次这个闭包, 拿到一份全新的 App 路由表22。

链式调用 .route(…) 返回的是被修改后的同一个 App;闭包体最后一行没有分号, 所以 App 是闭包的返回值——第 3 节「块的值」那条规定在闭包上原样生效。

4.3 derive:让编译器替你写代码

web 表单提交的是 n=42&m=56 这样的数据。处理函数想直接拿到一个 GcdParameters 结构体:

#[derive(Deserialize)]
struct GcdParameters { n: u64, m: u64, }

#[derive(Deserialize)] 还是属性,但作用升级了:它让 serde 这个 crate 在编译时检查这个类型, 自动生成「从表单数据解析出 GcdParameters」的代码——JSON(一种常见的文本数据格式)、YAML、TOML 也都能解析23。 于是请求处理函数可以直接把 web::Form<GcdParameters> 声明为参数, Actix 的类型系统保证:凡是不能从表单数据解析的类型,根本过不了编译24。

这里还顺带一个语法糖:结构体字段初始化可以简写成 Complex { re, im } 代替 Complex { re: re, im: im }(第 2 章的曼德博程序会用到); 而且 Rust 处处允许多余的尾逗号,多行列表以逗号收尾是标准风格——改动行时少碰标点,diff 更干净25。

原始字符串:HTML 的家

第一版服务器里那一大段 HTML 用的是原始字符串:r#"…"#——r 开头、两头用同样数量的 # 号包裹。原始字符串里不识别任何转义序列,双引号随便写, 所以满是属性的 HTML 不用每个引号都写 \"。唯一要想的是「结尾标记别在内容里提前出现」: 内容里有 "# 就用 r##"…"##,有几个井号保几层平安34。

post_gcd:校验、format! 与 400

处理表单提交的函数有两个细节值得收进笔记:

async fn post_gcd(form: web::Form<GcdParameters>) -> HttpResponse {
    if form.n == 0 || form.m == 0 {
        return HttpResponse::BadRequest()      // HTTP 400
            .content_type("text/html")
            .body("Computing the GCD with zero is boring.");
    }
    let response = format!(
        "The greatest common divisor of the numbers {} and {} is <b>{}</b>\n",
        form.n, form.m, gcd(form.n, form.m),
    );
    HttpResponse::Ok().content_type("text/html").body(response)
}
  • 先做参数校验:gcd 遇到 0 会 panic,所以在边界上直接回 400,把「不可能的状态」挡在函数体外;
  • format! 是 println! 的兄弟,不打印、返回字符串;要插值(把值填进字符串占位处)的不是简单变量名时, 用空 {} 占位、值按顺序作参数。返回值再被包进 HTTP 200 的响应体31。

路由注册就是把 .route("/gcd", web::post().to(post_gcd)) 再加一行—— GET 和 POST 各管一条路径,App 照旧是闭包的返回值32。

并发预告:你的第一个多线程程序已经写完了

本章最后一段(下一章的主角)先交代一个反直觉的事实:web 服务器就是那个多线程程序。 Actix 用线程池跑请求处理函数——同时来好几个请求,get_index 和 post_gcd 就可能在 好几个线程里同时执行。写这两个函数时我们脑子里完全没有并发,但 Rust 保证这安全: 「如果你的程序编译过了,它就是无数据竞争的。所有 Rust 函数都是线程安全的。」33

凭什么?眼下只能引用结论:第 3、4 章的规则会让「不安全的共享」编译不过。 本章只要带走这个反差——在别的语言里,这种「随手写、线程安全」是要花大钱买的; 在 Rust 里,它是编译通过的副产品。

5. 作者的判断与证据

这一章是「展示」,不是「论证」,但作者的判断仍然清晰可见:

  • 「如果程序编译过了,它就是无数据竞争的」——这句话在并发一节出现,是全书最大胆的承诺。 证据不是这章给的:它引用的保证来自第 3、4 章的所有权/借用规则,这章只演示「你随手写的两个请求处理函数 可能同时跑在好几个线程上,而这是安全的」26。
  • 「C 和 C++ 的并发名声很臭,Rust 把它洗白了」——作者明说这是他们的经验之谈, 特别是「数据搬去别的线程后,发送方还能不能摸到它」这种错,C 里要靠注释和自律,Rust 里编译器直接查27。
  • 「我们强烈鼓励你去翻在线文档」——原书反复指你到 rustup 自带的离线标准库文档(rustup doc --std), 这份文档连源码链接都有28。这是作者对读者学习路径的建议,不是广告。

哪些是推测:对 Actix、serde 这些第三方 crate 的选择是作者的口味(2025 年初的版本号); async 的性能承诺(「一个核伺候上千连接」)是框架的主张,原书没有在这章给出测量。

6. 边界与局限

  • 版本即日期:cargo 1.85、actix-web 4.9、serde 1.0.217 都是 2025 年初的快照, 你今天照搬会得到更新的版本号;机制不变,数字会变。
  • [Link to Come] 不是修辞:原书里 Cargo.toml 详解、trait 详解、async 详解 全部挂着占位符—— Early Release 还没放出那些章节。
  • web 程序的教学价值有限:它展示的是「Rust 在现实生态里怎么被使用」,但对理解 Rust 本身, 程序一和程序三的信息密度更高。
  • 程序二没有讲错误处理的完整形态:expect 一出错就整个进程退出,真实服务器不会这样—— 怎么把错误传回给调用方层层处理,在还没放出的「错误处理」一章。

7. 可带走的

主线例子一行版: 命令行参数 → u64::from_str 解析(失败就 expect 退出)→ 迭代 &numbers[1..] 逐个借元素 → 循环调 gcd → println! 按调试格式打印。

  1. Rust 没有「看家特性」,全部设计服务于「安全的、高性能的系统编程」这一目标;
  2. 三个工具分工:cargo 管一切日常(建/编/跑/依赖),rustc 是编译器,rustdoc 出文档;
  3. 函数参数和返回值类型必写,函数体内靠类型推断;
  4. 变量默认不可变,要改加 mut——这是给读者的提示,不是累赘;
  5. assert! 永远检查;panic 是 Rust 的「立即终止」,没有异常,错误走 Result;
  6. expect 是 Result 的「要么取值要么退出」;trait 必须在作用域内才能用它的方法;
  7. 迭代器无处不在且零成本;for x in &v 是借用遍历,for x in v 是消耗遍历;
  8. & 借引用、* 解引用;借用不转移所有权,所有者离开作用域时自动释放;
  9. crate 是 Rust 的包;Cargo.toml 记依赖,feature 要显式开;
  10. #[derive(...)] 让外部 crate 在编译期替你生成代码;#[test] 让测试住在源码里。

8. 原文地图

主题 原书章 原文位置
没有单一特性、目标定位 Chapter 1. A Tour of Rust text/04-ch01-chapter-1-a-tour-of-rust.txt:13(搜「what gives the language its character」)
rustup 与三命令 Chapter 1. A Tour of Rust text/04-ch01-chapter-1-a-tour-of-rust.txt:29(搜「rustup.rs」) · text/04-ch01-chapter-1-a-tour-of-rust.txt:44(搜「compilation manager」)
cargo new、九行样板 Chapter 1. A Tour of Rust text/04-ch01-chapter-1-a-tour-of-rust.txt:95(搜「nine lines」)
gcd 函数语法 Chapter 1. A Tour of Rust text/04-ch01-chapter-1-a-tour-of-rust.txt:142(搜「fn keyword」) · text/04-ch01-chapter-1-a-tour-of-rust.txt:148(搜「panic」) · text/04-ch01-chapter-1-a-tour-of-rust.txt:156(搜「return statement」)
单元测试与属性 Chapter 1. A Tour of Rust text/04-ch01-chapter-1-a-tour-of-rust.txt:175(搜「skipped in normal compilations」) · text/04-ch01-chapter-1-a-tour-of-rust.txt:177(搜「attribute」)
trait / FromStr Chapter 1. A Tour of Rust text/04-ch01-chapter-1-a-tour-of-rust.txt:224(搜「collection of methods」)
迭代器与零成本 Chapter 1. A Tour of Rust text/04-ch01-chapter-1-a-tour-of-rust.txt:244(搜「on demand」)
Result、无异常 Chapter 1. A Tour of Rust text/04-ch01-chapter-1-a-tour-of-rust.txt:256(搜「does not have exceptions」) · text/04-ch01-chapter-1-a-tour-of-rust.txt:258(搜「expect」)
& 与 *、自动释放 Chapter 1. A Tour of Rust text/04-ch01-chapter-1-a-tour-of-rust.txt:278(搜「borrows a reference」)
crate / crates.io / feature Chapter 1. A Tour of Rust text/04-ch01-chapter-1-a-tour-of-rust.txt:316(搜「freely available」) · text/04-ch01-chapter-1-a-tour-of-rust.txt:352(搜「latest compatible version」) · text/04-ch01-chapter-1-a-tour-of-rust.txt:354(搜「optional features」)
async 与闭包 Chapter 1. A Tour of Rust text/04-ch01-chapter-1-a-tour-of-rust.txt:395(搜「async」) · text/04-ch01-chapter-1-a-tour-of-rust.txt:399(搜「called as if it were a function」)
derive(Deserialize) Chapter 1. A Tour of Rust text/04-ch01-chapter-1-a-tour-of-rust.txt:446(搜「automatically generate」)
cargo 日常循环与 clean Chapter 1. A Tour of Rust text/04-ch01-chapter-1-a-tour-of-rust.txt:97(搜「cargo run」) · text/04-ch01-chapter-1-a-tour-of-rust.txt:120(搜「cargo clean」)
测试运行实录 Chapter 1. A Tour of Rust text/04-ch01-chapter-1-a-tour-of-rust.txt:186(搜「running 1 test」)
post_gcd 与 format! Chapter 1. A Tour of Rust text/04-ch01-chapter-1-a-tour-of-rust.txt:454(搜「BadRequest」)
并发预告:web 服务器即多线程 Chapter 1. A Tour of Rust text/04-ch01-chapter-1-a-tour-of-rust.txt:521(搜「pool of threads」)
编译过即无数据竞争 Chapter 1. A Tour of Rust text/04-ch01-chapter-1-a-tour-of-rust.txt:521(搜「All Rust functions are thread-safe」)

  1. 出处:「Chapter 1. A Tour of Rust」第 13 段(text/04-ch01-chapter-1-a-tour-of-rust.txt:13,搜「what gives the language its character」)。 ↩

  2. 出处:「Chapter 1. A Tour of Rust」第 29–31 段(text/04-ch01-chapter-1-a-tour-of-rust.txt:29-31,搜「RVM for Ruby」)。「像 RVM for Ruby 或 NVM for Node 一样管理 Rust 安装的工具」。 ↩

  3. 出处:「Chapter 1. A Tour of Rust」第 35–40 段(text/04-ch01-chapter-1-a-tour-of-rust.txt:35-40,搜「cargo 1.85.0」)。 ↩

  4. 出处:「Chapter 1. A Tour of Rust」第 50–95 段(text/04-ch01-chapter-1-a-tour-of-rust.txt:50-95,搜「two files, totaling nine lines」)。 ↩

  5. 出处:「Chapter 1. A Tour of Rust」第 316 段(text/04-ch01-chapter-1-a-tour-of-rust.txt:316,搜「called a crate」)。 ↩

  6. 出处:「Chapter 1. A Tour of Rust」第 142–152 段(text/04-ch01-chapter-1-a-tour-of-rust.txt:142-152,搜「fn keyword」与「infer」)。「Rust 只在函数体内推断类型:函数参数和返回值的类型必须写出。」 ↩

  7. 出处:「Chapter 1. A Tour of Rust」第 146 段(text/04-ch01-chapter-1-a-tour-of-rust.txt:146,搜「helpful hint」)。 ↩

  8. 出处:「Chapter 1. A Tour of Rust」第 148 段(text/04-ch01-chapter-1-a-tour-of-rust.txt:148,搜「always checks assertions」)。 ↩

  9. 出处:「Chapter 1. A Tour of Rust」第 150 段(text/04-ch01-chapter-1-a-tour-of-rust.txt:150,搜「curly braces」)。 ↩

  10. 出处:「Chapter 1. A Tour of Rust」第 175 段(text/04-ch01-chapter-1-a-tour-of-rust.txt:175,搜「skipped in normal compilations」)。 ↩

  11. 出处:「Chapter 1. A Tour of Rust」第 224 段(text/04-ch01-chapter-1-a-tour-of-rust.txt:224,搜「collection of methods」)。 ↩

  12. 出处:「Chapter 1. A Tour of Rust」第 236–238 段(text/04-ch01-chapter-1-a-tour-of-rust.txt:236-238,搜「growable vector」)。 ↩

  13. 出处:「Chapter 1. A Tour of Rust」第 244 段(text/04-ch01-chapter-1-a-tour-of-rust.txt:244,搜「same code as a handwritten loop」)。 ↩

  14. 出处:「Chapter 1. A Tour of Rust」第 256 段(text/04-ch01-chapter-1-a-tour-of-rust.txt:256,搜「does not have exceptions」)。 ↩

  15. 出处:「Chapter 1. A Tour of Rust」第 258 段(text/04-ch01-chapter-1-a-tour-of-rust.txt:258,搜「exits the program immediately」)。 ↩

  16. 出处:「Chapter 1. A Tour of Rust」第 274–280 段(text/04-ch01-chapter-1-a-tour-of-rust.txt:274-280,搜「complementary」与「borrows a reference」)。 ↩

  17. 出处:「Chapter 1. A Tour of Rust」第 288 段(text/04-ch01-chapter-1-a-tour-of-rust.txt:288,搜「finished successfully」)。 ↩

  18. 出处:「Chapter 1. A Tour of Rust」第 316–318 段(text/04-ch01-chapter-1-a-tour-of-rust.txt:316-318,搜「freely available」)。 ↩

  19. 出处:「Chapter 1. A Tour of Rust」第 352 段(text/04-ch01-chapter-1-a-tour-of-rust.txt:352,搜「latest compatible version」)。 ↩

  20. 出处:「Chapter 1. A Tour of Rust」第 354 段(text/04-ch01-chapter-1-a-tour-of-rust.txt:354,搜「optional features」)。 ↩

  21. 出处:「Chapter 1. A Tour of Rust」第 395 段(text/04-ch01-chapter-1-a-tour-of-rust.txt:395,搜「C# and JavaScript」)。 ↩

  22. 出处:「Chapter 1. A Tour of Rust」第 399–401 段(text/04-ch01-chapter-1-a-tour-of-rust.txt:399-401,搜「called as if it were a function」)。 ↩

  23. 出处:「Chapter 1. A Tour of Rust」第 446 段(text/04-ch01-chapter-1-a-tour-of-rust.txt:446,搜「automatically generate」)。 ↩

  24. 出处:「Chapter 1. A Tour of Rust」第 472 段(text/04-ch01-chapter-1-a-tour-of-rust.txt:472,搜「worked out at compile time」)。 ↩

  25. 出处:「Chapter 1. A Tour of Rust」第 448 段(text/04-ch01-chapter-1-a-tour-of-rust.txt:448,搜「trailing comma」)。字段简写见「Parsing Pair Command-Line Arguments」第 97 段(text/06-fm-parsing-pair-command-line-arguments.txt:97,搜「shorthand」)。 ↩

  26. 出处:「Chapter 1. A Tour of Rust」第 521 段(text/04-ch01-chapter-1-a-tour-of-rust.txt:521,搜「All Rust functions are thread-safe」)。 ↩

  27. 出处:「Chapter 1. A Tour of Rust」第 511–517 段(text/04-ch01-chapter-1-a-tour-of-rust.txt:511-517,搜「left to the comments」)。三条对照(互斥锁、只读共享、所有权转移)里作者的原话:「不是我们要抱怨。」(Not that we're bitter.) ↩

  28. 出处:「Chapter 1. A Tour of Rust」第 310 段(text/04-ch01-chapter-1-a-tour-of-rust.txt:310,搜「live search」)。 ↩

  29. 出处:「Chapter 1. A Tour of Rust」第 97–123 段(text/04-ch01-chapter-1-a-tour-of-rust.txt:97-123,搜「cargo clean」)。 ↩

  30. 出处:「Chapter 1. A Tour of Rust」第 179–190 段(text/04-ch01-chapter-1-a-tour-of-rust.txt:179-190,搜「running 1 test」)。 ↩

  31. 出处:「Chapter 1. A Tour of Rust」第 452–474 段(text/04-ch01-chapter-1-a-tour-of-rust.txt:452-474,搜「format!」)。 ↩

  32. 出处:「Chapter 1. A Tour of Rust」第 476–495 段(text/04-ch01-chapter-1-a-tour-of-rust.txt:476-495,搜「/gcd」)。 ↩

  33. 出处:「Chapter 1. A Tour of Rust」第 519–521 段(text/04-ch01-chapter-1-a-tour-of-rust.txt:519-521,搜「thread-safe」)。 ↩

  34. 出处:「Chapter 1. A Tour of Rust」第 405 段(text/04-ch01-chapter-1-a-tour-of-rust.txt:405,搜「raw string」)。 ↩