跳转至

所有权 — 内存管理的死结与 Rust 的第三条路

这一章讲一件事: 内存管理有一个看起来解不开的死结,所有主流语言都放弃了一半; Rust 用「每个值只能有一个主人」这条规矩把死结解开——而解开的方式是限制你能写的程序, 不是给运行时加机制。这是全书最重要的一章,后面的每一章都建立在这章的地基上。

1. 顶层全景:从死结到解法

  想要的两件事:① 内存在我选定的时间被释放   ② 绝不用指向已释放内存的指针
      │ 矛盾:指针还活着就释放,指针就悬垂了
      ▼
  现有语言二选一:
    安全优先派(垃圾回收)── 放弃①,释放时机归回收器(Python/Java/JS…)
    控制优先派(手动 free)── 放弃②,悬垂指针的风险归你(C/C++)
      │
      ▼
  Rust 的第三条路:给指针用法立规矩
    规则1 每个值恰有一个所有者,主人死则值死
    规则2 赋值/传参/返回 = 移动所有权,源变量作废
      │
      ▼
  效果:释放时机像 C++ 一样清楚,赋值代价像 Python 一样便宜

图说:两派的代价 Rust 都不付,它付的是第三种代价——写法受限。

2. 死结的定义:你想要的两件事互斥

原书开头把问题摆得很干净。管理内存想要两个性质:

  1. 内存及时释放,释放时机由我定——这样内存占用可控;
  2. 绝不使用指向已释放对象的指针——否则就是未定义行为:崩溃、安全洞1。

但这两件事打架:值还有指针指着,你就把它放了,指针就悬垂。 于是几乎所有语言按「放弃哪一件」分两派:

「安全优先」派:用垃圾回收。对象留着不放的指针一个不剩,才允许释放—— 悬垂指针被「让对象多活一会儿」消灭了;代价是释放时机归回收器管,而回收器 「是个惊人的野兽」,为什么内存没在你预期时释放,可能很费解2。 Python、JavaScript、Ruby、Java、C#、Haskell 全在这派。

「控制优先」派:释放归你。内存占用完全在手,但避免悬垂指针也完全归你。 C 和 C++ 是唯一的主流成员3。证据不太妙:自有安全漏洞统计以来,指针误用一直是常客4。

Rust 两个妥协都不接受。而如果调和容易,早有人做了——所以「必须有某种根本性的东西要改变」5。

3. 第三条路:规矩立在编译期

Rust 的解法一句话:给程序使用指针的方式立一些限制,净效果是给混沌带来刚好足够的秩序, 让编译期检查能验证你的程序没有内存安全错误6。

拆开来是两条承诺:

  • 编译期:Rust 记录每个值在哪里创建、在哪里使用,跟踪所有权的流转, 防止使用未初始化的值、保证每个值恰好释放一次、且只在不再需要时释放(消灭 double-free); 同时分析引用,防止悬垂指针6。
  • 运行时:指针就是普通内存地址,和 C/C++ 一模一样——省下的成本全在编译期付6。

同一套规则还是 Rust 并发安全的地基(线程怎么共享内存才安全,由同一套规则证明)——这是后面章节的展开7。

作者把这叫做「Rust 的激进赌注(radical wager)**:即使带着这些限制, 语言对几乎所有任务仍然足够灵活,而消灭一大类内存与并发 bug 的收益, 值得你调整写法。作者明说立场:他们是 C/C++ 老手,这笔交易「不用想」8。 学 Rust 的中心挑战,不是语法,是学会利用这套规则9。

4. 所有权:C++ 注释里的约定,变成语言规则

C++ 代码里常见这类注释:「这个对象 own(拥有)它指向的那个对象」—— 意思是:拥有者决定被拥有者什么时候释放;拥有者销毁时被拥有物跟着销毁。 C++ 的 std::string 就是例子:字符串本体恒为三个机器字(指向堆缓冲的指针、容量、长度), 它拥有那个缓冲,析构时释放10。

但这在 C++ 里只是约定:语言鼓励你这么做,你自己设计的类型要不要遵守,随你11。

Rust 把这条约定变成了编译期强制的语言规则:每个值有恰好一个所有者,主人决定它活多久; 主人被释放(dropped,丢弃)时,值跟着被释放。 好处是:值的寿命从代码上一眼就能找到12。

具体规则:

  • 变量拥有它的值。控制流离开变量声明的块,变量被丢弃,值跟着被丢弃;
  • 结构体拥有字段,数组/向量拥有元素。Vec<Person> 的向量拥有每个 Person 结构, 每个结构拥有它的 String 字段,String 拥有它的文本缓冲;
  • Box<T> 是最简单的堆拥有者:Box::new(v) 在堆上给 v 分配空间、把 v 搬进去、返回指向它的 Box; Box 被丢弃时,那块空间跟着释放13。

C++ 的 owns 约定,与它的松动史

所有权概念不是 Rust 发明的——C++ 代码里的 owns 注释才是它的祖宅。原书把 C++ 的 std::string 当标本,还附了一段库里短史33:

  • 字符串本体恒为三个机器字:指向堆缓冲的指针、容量、长度;
  • 它拥有那个缓冲:字符串销毁,缓冲跟着释放;
  • 早年有库让多个 string 共享一块缓冲、用引用计数决定何时释放;
  • 较新的 C++ 规范实质上禁掉了那种表示,如今所有现代库都用独占式。

这段历史里有个重要的对照:C++ 的「拥有」从头到尾是约定——标准库普遍遵守, 语言也鼓励,但你设计的类型遵不遵守,语言不管34。Rust 做的事本质上是把这个约定 收编成法律:每个值恰有一个主人,写入语言、编译期执法35。

还有一条约定比拥有更隐蔽:别人可以临时指向我的缓冲,但在主人销毁之前必须收手。 「主人决定被拥有者的寿命,其他人必须尊重它的决定」——C 里这句话靠注释和自觉, Rust 里它就是借用规则(下一章)36。

5. 所有权树:规则拼出来的形状

把上面的关系连起来看,会有一个几何结论:所有者与被拥有者构成树—— 你的所有者是你的父节点,你拥有的值是你的子节点;每棵树的根是某个变量, 变量一出作用域,整棵树随之销毁14。

书里 composers 向量的例子:composers 拥有向量 → 向量拥有 3 个 Person 元素 → 每个 Person 拥有 name 字段 → 每个 String 拥有它的文本。四层的树15。

两个推论:

  1. 「释放」从来不显式写。C/C++ 里你要写 free/delete;Rust 里让值脱离所有权树就行—— 离开作用域、从向量删掉元素……Rust 保证把它连同它拥有的一切妥善丢弃16。
  2. 单 owner 规则禁止任何「重新汇合」的结构——环形、菱形,凡能让图比树复杂的都不行14。

第一现场:一个向量的一生

书上的第一个所有权例子朴素得值得抄一遍——帕多瓦数列(Padovan sequence,类似斐波那契的递推数列):

fn print_padovan() {
    let mut padovan = vec![1, 1, 1];          // 在这里分配
    for i in 3..10 {
        let next = padovan[i-3] + padovan[i-2];
        padovan.push(next);
    }
    println!("P(1..10) = {padovan:?}");
}                                             // 在这里释放

padovan 的类型是 Vec<i32>。内存里它长这样:栈上的 print_padovan 栈帧里躺着三个机器字 (指向堆缓冲的指针、容量、长度),只有元素缓冲本身在堆上26。

关键在这一头一尾:向量拥有那个缓冲——变量 padovan 出作用域,程序丢弃向量, 向量带着缓冲一起死。没有 free,没有 delete,没有析构函数要写; 「谁拥有」这个问题,从声明处到作用域末尾一眼看完27。

第二现场:Box 与堆上的点

Box<T> 是最简单的「我要在堆上放一个值」:

{
    let point = Box::new((0.625, 0.5));   // 堆上分配,Box 指向它
    let label = format!("{point:?}");     // label 是另一个堆分配的 String
    assert_eq!(label, "(0.625, 0.5)");
}   // point 和 label 一起死,各自带着自己的堆内存

到 assert 执行时,栈帧里两个局部变量,各自拥有一块堆内存。 Box 的规则和变量一样:Box 被丢弃,它指的那块空间跟着释放28。

再叠一层:struct Person { name: String, birth: i32 },造一个 Vec<Person> 往里 push 几个作曲家 (Palestrina、Dowland、Lully)——拥有关系立刻变成四层:composers 拥有向量,向量拥有每个 Person, 每个 Person 拥有 name 字段,每个 String 拥有它的文本。控制流离开 composers 的作用域, 整棵四层树一次性拆掉,换别的集合类型(HashMap、BTreeSet)故事一字不改29。

松动预告:原书列好的四张底牌

树太死怎么办?原书在这一章开头就把答案全亮了出来,后面两章逐一兑现37:

  1. 移动:把值从一个主人过户给另一个主人——建、拆、重组树都靠它(本章后半);
  2. Copy 类型:整数这类简单值免除所有权规则,按位复制、源照用(下一章);
  3. Rc/Arc:实在需要多主人时,用引用计数指针共享——有限制的例外(下一章);
  4. 借用:不接管所有权,只临时指向——用得最多的口子,下一章整章给它。

四张底牌没有一张是「破坏规则」,全是「规则之内的口子」——这是理解 Rust 设计的关键: 它不是靠不断破例换取灵活,而是把口子本身也设计成受规则约束的类型。

树的几何后果:少即是多

所有权树还有一层含义,原书点得很透:其他语言允许你把对象连成任意形状的图, Rust 不许——单主人规则禁止任何「重新汇合」的结构。环形、菱形、互相指,都得另想办法(计数指针、借用)。

这不是纯粹的损失,而是交易的明账:「正因为 Rust 更弱,它能对你的程序做的分析才更强—— 安全保证之所以可能,恰恰因为代码里可能出现的关系更可处理。」表达力换可分析性, 这是 Rust 全部设计的总账38。

释放的出口有三个

值脱离所有权树的方式,书里点名的就三种:离开变量的作用域、从集合里删掉元素、 或类似的手艺。出口一出现,Rust 负责把这个值连同它拥有的一切妥善丢弃—— 所以 Rust 程序里找不到 free 和 delete,释放不是动作,是所有权变更的副作用39。

6. 主线例子:三行赋值,三种语言,三种世界

现在走本章的主线例子。同一件事——把一串字符串向量赋给另外两个变量—— 在三种语言里各自的内存结局:

let s = vec!["udon".to_string(), "ramen".to_string(), "soba".to_string()];
let t = s;
let u = s;   // ← Rust 在这里报错

Python 版:t = s 不复制对象,只把指针复制一份、引用计数加一。 便宜,但必须维护引用计数(更一般地,要垃圾回收)才知道何时释放17。

C++ 版:赋值是深复制——整个向量连同 9 个字符串全部重新分配。 产权清晰(出作用域自动清理),但代价可以无上限:复制多少内存、花多少时间,看值有多大18。

Rust 版:初始化 let t = s; 把向量的头部(头部字段,即指针、容量、长度这三个机器字)从 s 搬到 t; 元素留在原地没动,字符串也没动;没有引用计数要调;编译器现在认为 s 是未初始化的19。 再写 let u = s; 就是使用未初始化的值,被拒:

error: use of moved value: `s`
 7 | let t = s;
   |         - value moved here
 8 | let u = s;
   |         ^ value used here after move

作者的评价:Rust 像 Python 一样便宜(只搬三个机器字),又像 C++ 一样产权清晰 (无需计数器就知道何时释放元素和文本)。代价:想要复制得明说—— 调 s.clone() 做一次深复制,回到 C++ 那版的状态20。

7. 移动不只发生在赋值处

移动语义覆盖几乎所有「使用值」的场合:

场合 发生了什么
初始化 let t = s; 所有权进 t,s 作废
赋值给已有变量 先丢弃旧值,再移入新值(但若 s 已经搬走,就不丢东西)21
函数传参 所有权进参数,函数用完即弃
函数返回 所有权回到调用方
造元组/结构体 值搬进新值里
vec.push(x) 值搬进向量,向量成为间接主人22

为什么这不慢:移动永远只动「值本体」——向量/字符串的本体就是那三个机器字, 堆上的大家伙原地不动;而且编译器的代码生成常能看穿移动序列, 直接把值存进它最终该在的位置23。

报错的全文:编译器怎么向你描述「已搬走」

再欣赏一次那条报错——它是理解移动语义的免费教材30:

error: use of moved value: `s`
  |
7 | let s = vec!["udon".to_string(), "ramen".to_string(), "soba".to_string()];
  |     - move occurs because `s` has type `Vec<String>`,
  |       which does not implement the `Copy` trait
8 | let t = s;
  |         - value moved here
9 | let u = s;
  |         ^ value used here after move

三行箭头,三个信息:s 是什么类型;它在哪一行被搬走;它在哪一行被违规使用。 报错里的术语「the Copy trait」先混个脸熟——下一章会讲,这里只需知道: 类型不 Copy,赋值就过户31。

为什么搬来搬去也不怕慢

两个理由,都来自「值的本体很小」这个事实:

  1. 移动永远只动值本体。向量的本体是栈上的三个机器字;堆上那串字符串原地不动, 新主人通过同一个指针找到它们。「搬」一个看起来很大的对象,代价等于复制三个整数;
  2. 编译器看得穿移动。源码层面「先搬进 t、再搬一次、最后存进结构体」的写法, 生成机器码时常被合并成「直接存进最终该在的位置」。 移动是语义规定,不是一次运行时拷贝32。

8. 作者的判断与证据

  • 「Rust 因此比别的语言『弱』」——作者自己说的:其他语言任你把对象连成任意形状的图, Rust 不行。「但正因为 Rust 更弱,它能对你的程序做的分析才更强: 安全保证之所以可能,恰恰因为代码里可能出现的关系更可处理。」24 这是全章最诚实的一句:安全是表达力换来的。
  • 「实践中灵活度足够」是赌注本身,不是已证事实——作者承认这是「radical wager」8。
  • 「C/C++ 程序员对深复制意见很大」是经验观察,作为移动语义的存在理由18。

9. 边界与局限

  • 所有权树的论证假设程序不用 unsafe;裸指针可以造出任何形状,但那是显式退出保证的地带;
  • 循环结构(两个值互相拥有)在纯所有权模型里写不出来——第 6 章的 Rc/内部可变性才补这个洞, 本章只预告25;
  • 「值恰好释放一次」依赖编译期追踪,第 4 章的引用规则才是完整的检查;
  • 移动语义与 FFI 的交互(C 调用约定下怎么传)本章未涉及。

10. 可带走的

主线例子一行版: 三个语言的 t = s ——Python 复制指针加计数,C++ 深复制一切,Rust 只搬三个机器字、源作废。

  1. 内存管理死结:及时释放 vs 永不悬垂,互斥;垃圾回收放弃前者,手动管理放弃后者;
  2. Rust 第三条路:限制指针用法,编译期证明安全;运行时指针就是普通地址;
  3. 每个值恰有一个所有者;主人被丢弃,值跟着被丢弃——值的寿命从代码上一眼可见;
  4. 所有权关系拼成树,树根是变量;Rust 不许比树更复杂的结构;
  5. 释放从不显式写:让值脱离所有权树,剩下的自动发生;
  6. 赋值/传参/返回默认是移动:只搬值本体(三个机器字),堆数据原地不动;
  7. 移动后源是未初始化,再用即编译错误;想要复制就显式 clone();
  8. 「Rust 更弱所以分析更强」:安全是限制表达力换来的,这是设计不是缺陷;
  9. 学 Rust 的中心挑战是学会利用规则,不是背语法;
  10. 这套规则同时是并发安全的地基——数据竞争的形状被规则预先排除(第 4 章展开)。

11. 原文地图

主题 原书章 原文位置
两个想要的性质 Chapter 3. Ownership and Moves text/13-ch03-chapter-3-ownership-and-moves.txt:15(搜「freed promptly」)
两派之分 Chapter 3. Ownership and Moves text/13-ch03-chapter-3-ownership-and-moves.txt:21(搜「Safety First」) · text/13-ch03-chapter-3-ownership-and-moves.txt:25(搜「Control First」)
第三条路总述 Chapter 3. Ownership and Moves text/13-ch03-chapter-3-ownership-and-moves.txt:31(搜「bring just enough order」)
激进赌注 Chapter 3. Ownership and Moves text/13-ch03-chapter-3-ownership-and-moves.txt:37(搜「radical wager」)
中心挑战 Chapter 3. Ownership and Moves text/13-ch03-chapter-3-ownership-and-moves.txt:39(搜「central challenge」)
C++ 的 owns 约定 Chapter 3. Ownership and Moves text/13-ch03-chapter-3-ownership-and-moves.txt:43(搜「owns some other object」)
单所有者规则 Chapter 3. Ownership and Moves text/13-ch03-chapter-3-ownership-and-moves.txt:61(搜「single owner」)
Box 拥有堆空间 Chapter 3. Ownership and Moves text/13-ch03-chapter-3-ownership-and-moves.txt:82(搜「Box::new」)
所有权树 Chapter 3. Ownership and Moves text/13-ch03-chapter-3-ownership-and-moves.txt:121(搜「form trees」)
不显式 drop Chapter 3. Ownership and Moves text/13-ch03-chapter-3-ownership-and-moves.txt:123(搜「explicitly drop」)
Python 赋值语义 Chapter 3. Ownership and Moves text/13-ch03-chapter-3-ownership-and-moves.txt:157(搜「reference count」)
C++ 深复制 Chapter 3. Ownership and Moves text/13-ch03-chapter-3-ownership-and-moves.txt:172(搜「nine strings」)
移动语义定义 Chapter 3. Ownership and Moves text/13-ch03-chapter-3-ownership-and-moves.txt:141(搜「relinquishes ownership」)
三机器字头部 Chapter 3. Ownership and Moves text/13-ch03-chapter-3-ownership-and-moves.txt:198(搜「three header fields」)
clone 显式复制 Chapter 3. Ownership and Moves text/13-ch03-chapter-3-ownership-and-moves.txt:214(搜「deep copy」)
移动的更多场合 Chapter 3. Ownership and Moves text/13-ch03-chapter-3-ownership-and-moves.txt:237(搜「Returning a value」)
移动为何高效 Chapter 3. Ownership and Moves text/13-ch03-chapter-3-ownership-and-moves.txt:261(搜「seeing through」)
padovan 向量的一生 Chapter 3. Ownership and Moves text/13-ch03-chapter-3-ownership-and-moves.txt:66(搜「allocated here」)
Box 与堆上的点 Chapter 3. Ownership and Moves text/13-ch03-chapter-3-ownership-and-moves.txt:87(搜「point allocated here」)
报错全文与移动的成本 Chapter 3. Ownership and Moves text/13-ch03-chapter-3-ownership-and-moves.txt:202(搜「use of moved value」) · text/13-ch03-chapter-3-ownership-and-moves.txt:261(搜「seeing through」)
C++ owns 约定的历史 Chapter 3. Ownership and Moves text/13-ch03-chapter-3-ownership-and-moves.txt:55(搜「shared a single buffer」)
松动预告四张底牌 Chapter 3. Ownership and Moves text/13-ch03-chapter-3-ownership-and-moves.txt:127(搜「too rigid」)
「更弱所以更强」 Chapter 3. Ownership and Moves text/13-ch03-chapter-3-ownership-and-moves.txt:125(搜「less powerful」)

  1. 出处:「Chapter 3. Ownership and Moves」第 15–17 段(text/13-ch03-chapter-3-ownership-and-moves.txt:15-17,搜「freed promptly」)。 ↩

  2. 出处:「Chapter 3. Ownership and Moves」第 21–23 段(text/13-ch03-chapter-3-ownership-and-moves.txt:21-23,搜「Safety First」)。 ↩

  3. 出处:「Chapter 3. Ownership and Moves」第 25 段(text/13-ch03-chapter-3-ownership-and-moves.txt:25,搜「Control First」)。 ↩

  4. 出处:「Chapter 3. Ownership and Moves」第 27 段(text/13-ch03-chapter-3-ownership-and-moves.txt:27,搜「common culprit」)。 ↩

  5. 出处:「Chapter 3. Ownership and Moves」第 29 段(text/13-ch03-chapter-3-ownership-and-moves.txt:29,搜「Something fundamental had to change」)。 ↩

  6. 出处:「Chapter 3. Ownership and Moves」第 31 段(text/13-ch03-chapter-3-ownership-and-moves.txt:31,搜「bring just enough order」)。 ↩↩↩

  7. 出处:「Chapter 3. Ownership and Moves」第 35 段(text/13-ch03-chapter-3-ownership-and-moves.txt:35,搜「data races」)。 ↩

  8. 出处:「Chapter 3. Ownership and Moves」第 37 段(text/13-ch03-chapter-3-ownership-and-moves.txt:37,搜「radical wager」)。 ↩↩

  9. 出处:「Chapter 3. Ownership and Moves」第 39 段(text/13-ch03-chapter-3-ownership-and-moves.txt:39,搜「central challenge」)。 ↩

  10. 出处:「Chapter 3. Ownership and Moves」第 53 段(text/13-ch03-chapter-3-ownership-and-moves.txt:53,搜「three words long」)。 ↩

  11. 出处:「Chapter 3. Ownership and Moves」第 59 段(text/13-ch03-chapter-3-ownership-and-moves.txt:59,搜「convention」)。 ↩

  12. 出处:「Chapter 3. Ownership and Moves」第 61 段(text/13-ch03-chapter-3-ownership-and-moves.txt:61,搜「single owner」)。 ↩

  13. 出处:「Chapter 3. Ownership and Moves」第 63–96 段(text/13-ch03-chapter-3-ownership-and-moves.txt:63-96,搜「Box::new」)。 ↩

  14. 出处:「Chapter 3. Ownership and Moves」第 121 段(text/13-ch03-chapter-3-ownership-and-moves.txt:121,搜「form trees」)。 ↩↩

  15. 出处:「Chapter 3. Ownership and Moves」第 100–117 段(text/13-ch03-chapter-3-ownership-and-moves.txt:100-117,搜「tree of ownership」)。 ↩

  16. 出处:「Chapter 3. Ownership and Moves」第 123 段(text/13-ch03-chapter-3-ownership-and-moves.txt:123,搜「explicitly drop」)。 ↩

  17. 出处:「Chapter 3. Ownership and Moves」第 157–161 段(text/13-ch03-chapter-3-ownership-and-moves.txt:157-161,搜「reference count」)。 ↩

  18. 出处:「Chapter 3. Ownership and Moves」第 172–180 段(text/13-ch03-chapter-3-ownership-and-moves.txt:172-180,搜「nine strings」)。 ↩↩

  19. 出处:「Chapter 3. Ownership and Moves」第 198 段(text/13-ch03-chapter-3-ownership-and-moves.txt:198,搜「three header fields」)。 ↩

  20. 出处:「Chapter 3. Ownership and Moves」第 212–218 段(text/13-ch03-chapter-3-ownership-and-moves.txt:212-218,搜「deep copy」)。 ↩

  21. 出处:「Chapter 3. Ownership and Moves」第 224–235 段(text/13-ch03-chapter-3-ownership-and-moves.txt:224-235,搜「prior value」)。 ↩

  22. 出处:「Chapter 3. Ownership and Moves」第 249–259 段(text/13-ch03-chapter-3-ownership-and-moves.txt:249-259,搜「push method」)。 ↩

  23. 出处:「Chapter 3. Ownership and Moves」第 261 段(text/13-ch03-chapter-3-ownership-and-moves.txt:261,搜「seeing through」)。 ↩

  24. 出处:「Chapter 3. Ownership and Moves」第 125 段(text/13-ch03-chapter-3-ownership-and-moves.txt:125,搜「less powerful」)。 ↩

  25. 出处:「Chapter 3. Ownership and Moves」第 127–135 段(text/13-ch03-chapter-3-ownership-and-moves.txt:127-135,搜「too rigid」)。 ↩

  26. 出处:「Chapter 3. Ownership and Moves」第 74–78 段(text/13-ch03-chapter-3-ownership-and-moves.txt:74-78,搜「three words」)。 ↩

  27. 出处:「Chapter 3. Ownership and Moves」第 80 段(text/13-ch03-chapter-3-ownership-and-moves.txt:80,搜「goes with it」)。 ↩

  28. 出处:「Chapter 3. Ownership and Moves」第 82–96 段(text/13-ch03-chapter-3-ownership-and-moves.txt:82-96,搜「heap」)。 ↩

  29. 出处:「Chapter 3. Ownership and Moves」第 100–117 段(text/13-ch03-chapter-3-ownership-and-moves.txt:100-117,搜「story would be the same」)。 ↩

  30. 出处:「Chapter 3. Ownership and Moves」第 202–210 段(text/13-ch03-chapter-3-ownership-and-moves.txt:202-210,搜「use of moved value」)。 ↩

  31. 出处:「Chapter 3. Ownership and Moves」第 206 段(text/13-ch03-chapter-3-ownership-and-moves.txt:206,搜「Copy` trait」)。 ↩

  32. 出处:「Chapter 3. Ownership and Moves」第 261 段(text/13-ch03-chapter-3-ownership-and-moves.txt:261,搜「seeing through」)。 ↩

  33. 出处:「Chapter 3. Ownership and Moves」第 53–55 段(text/13-ch03-chapter-3-ownership-and-moves.txt:53-55,搜「shared a single buffer」)。 ↩

  34. 出处:「Chapter 3. Ownership and Moves」第 59 段(text/13-ch03-chapter-3-ownership-and-moves.txt:59,搜「up to you」)。 ↩

  35. 出处:「Chapter 3. Ownership and Moves」第 61 段(text/13-ch03-chapter-3-ownership-and-moves.txt:61,搜「enforced by compile-time checks」)。 ↩

  36. 出处:「Chapter 3. Ownership and Moves」第 57 段(text/13-ch03-chapter-3-ownership-and-moves.txt:57,搜「respect its decisions」)。 ↩

  37. 出处:「Chapter 3. Ownership and Moves」第 127–135 段(text/13-ch03-chapter-3-ownership-and-moves.txt:127-135,搜「too rigid」)。 ↩

  38. 出处:「Chapter 3. Ownership and Moves」第 125 段(text/13-ch03-chapter-3-ownership-and-moves.txt:125,搜「more powerful」)。 ↩

  39. 出处:「Chapter 3. Ownership and Moves」第 123 段(text/13-ch03-chapter-3-ownership-and-moves.txt:123,搜「ownership tree」)。 ↩