跳转至

数组、向量与字符串 — 基本类型(下)

这一章讲两件事: 数组、向量、切片这三个序列(一个接一个排成一列的值)类型谁干什么、怎么互相转; String 和 &str 为什么是两个类型、len() 为什么经常「数错」。 上一章讲原子,这一章讲由原子组成的第一批分子——后面所有数据结构都长在这层上。

1. 顶层全景:三种序列,一条借用链

  [T; N]  数组:定长,长度是类型的一部分,在栈上
      │  太长/要运行时定长?
      ▼
  Vec<T>  向量:堆上,可增长 = 指针 + 容量 + 长度 三个机器字
      │  只想借一段,不想接管?
      ▼
  &[T] / &mut [T]  切片引用:胖指针 = 数据地址 + 元素个数

图说:从左到右,拥有的程度递减、灵活性递增。函数参数几乎总该选最右边那个。

本章的主线例子是曼德博程序里那个像素缓冲:1200 万字节怎么从 vec! 创建、 怎么被 render(&mut [u8]) 借用、最后怎么被 write_image(&[u8]) 只读借用——三种序列类型各走一步。

2. 数组:长度写进类型里

[T; N] 是定长数组:长度是编译期常量,是类型的一部分,不能伸缩1。两种写法:

let lazy_caterer: [u32; 6] = [1, 2, 4, 7, 11, 16];  // 逐个列
let mut sieve = [true; 10000];                        // [值; 个数]:一万个 true

[0u8; 1024] 是经典用法:一个 1 KB 的零填充缓冲区。有个细节很 Rust: 没有「未初始化数组」的写法——一般说来,Rust 保证代码永远碰不到未初始化的值2。

下标越界会怎样?Rust 每次访问都检查,越界就 panic——不是 undefined behavior,不是静默读错内存3。 下标类型还必须是 usize(别的整数类型不行)4。

有个语法边界:长度是变量时不能写 [true; n]——需要运行时定长就用向量5。

3. 向量:三个机器字加一个堆块

Vec<T> 是可增长序列,元素住堆里。创建姿势:

let mut primes = vec![2, 3, 5, 7];      // vec! 宏
let v: Vec<i32> = (0..5).collect();     // 从迭代器收集(类型要显式给)

vec![v; n] 建 n 个 v 的副本;collect 能造好几种集合,所以得告诉它你要 Vec<i32>6。

向量的内部结构是三个机器字:指向堆缓冲的指针、容量(这块缓冲最多装几个)、长度(现在装几个)。 容量满了再 push,就分配更大的缓冲、拷贝过去、更新指针和容量、释放旧的7。 知道大概需要多少就先 Vec::with_capacity(n),免去中途反复重分配——collect 内部就是这么优化的8。 capacity() 能看容量:往容量 2 的向量 push 第 3 个元素后,容量通常变 4(不保证恰好,只保证够用)9。

改内容的操作都有:中间插删(insert/remove,后面的元素要整体搬家,长向量上慢)、 pop 弹尾元素——注意 pop 返回 Option<T>:空向量弹不出东西,是 None 而不是报错10。

数组的活用:一万个 bool 当筛子

原书用一个经典小算法展示 [V; N] 语法——埃拉托斯特尼筛法找素数:

let mut sieve = [true; 10000];
for i in 2..100 {
    if sieve[i] {
        let mut j = i * i;          // 从 i² 开始划掉倍数
        while j < 10000 {
            sieve[j] = false;
            j += i;
        }
    }
}
assert!(sieve[211]);     // 211 是素数
assert!(!sieve[9876]);   // 9876 不是

[true; 10000] 一次造出一万个 true,不用写一万遍——这就是「定长缓冲」语法的典型用途30。

向量的实战小例子:按名字长度分类

原书还有一个调皮的小程序,顺带演示「收集迭代器」和「遍历向量」:

let languages: Vec<String> = std::env::args().skip(1).collect();
for l in languages {
    println!("{l}: {}", if l.len() % 2 == 0 { "functional" } else { "imperative" });
}

命令行传入 Lisp、Scheme、C、C++、Fortran,输出:

Lisp: functional
Scheme: functional
C: imperative
C++: imperative
Fortran: imperative

原书自己抖的包袱:「函数式语言的一个令人满意的定义,终于得出来了。」31 (按名字长度奇偶分类只是个玩笑,但这个例子里 collect 把参数迭代器收成 Vec<String>、 for 逐个消费——两个惯用法都是真的。)

4. 切片:序列的「视图」

切片 [T](不带长度)是数组或向量里的一段。它本身不能存进变量、不能直接传参—— 总是借引用出现:&[T] 或 &mut [T]11。

为什么切片引用要单独是个类型?因为它和普通引用不一样,是胖指针(fat pointer): 普通引用 &T 是一个机器字(地址);切片引用是两个——数据地址 + 元素个数12。

切片是这条借用链的枢纽,三个证据:

  • 数组和向量「自动降级」成切片:print(&a)、print(&v)、print(&v[0..2]) 都喂给同一个 fn print(n: &[f64])13。
  • 数组/向量好用的方法(sort、reverse、len)其实都定义在切片上—— 调用时 Rust 隐式借一个覆盖整体的切片出来14。
  • 函数参数该要切片就要切片:参数写 &Vec<f64> 就只收完整向量,&v[0..2] 都传不进去; 写 &[f64] 则数组、向量、片段通吃。原书把这当一条通用建议:能收切片引用就别收向量/数组引用15。

回到主线例子:曼德博的 render(pixels: &mut [u8], …) 收的是可变切片—— 它不关心这 1200 万字节来自整个向量还是哪条带,往里写就是了; write_image(pixels: &[u8], …) 收共享切片,保证写文件的人只读16。 并发版里 chunks_mut 把整缓冲切成互不重叠的可变切片,正是这一层的直接运用。

切片的区间语法与边界检查

取一段的写法是一个区间:&v[0..2](头两个)、&a[2..](从 2 到尾)、&sv[1..3](切片再切片)。 规则和下标访问一样:越界就 panic——想借一段超出数据末尾的切片,编译器放过你(下标是运行时的), 运行时在边界检查上拦住32。

为什么函数参数推荐切片?书里给的完整论证是:若 print 收 &Vec<f64>,就只能收完整向量, &v[0..2] 这种片段传不进去;收 &[f64] 则来者不拒。接口按切片设计,实现者自由,调用者也自由—— sort、reverse 定义在切片上而非 Vec<T> 上,就是这个原则的既有实践33。

5. String 与 &str:抄 Vec 与 &[T] 的作业

字符串在 Rust 里是两个类型,关系照抄向量那一对:

Vec<T> String
拥有缓冲、可增长、自动释放 是 是
::new() / ::with_capacity() 有 有
.reserve() / .capacity() 有 有
.push() / .pop() 有 有
区间切片 &v[a..b] 得 &[T] 得 &str
&Vec<T> 自动转 &[T] &String → &str
方法继承自 &[T] &str

原书原话:「&str 很像 &[T];String 类比 Vec<T>。」17

内存布局:String 是一个堆上缓冲、持有它、内容保证是合法 UTF-8(实现上就是 「保证内容形式良好的 Vec<u8>」);&str 是胖指针——借来的 UTF-8 文本,地址加长度18。 字符串字面量(如 "ಠ_ಠ")是 &str,指向程序机器码旁边那块只读内存,程序启动就在、退出才走19。

char 是另一回事:一个 char 占 4 字节,它存一个独立字符在 Unicode(全世界字符的统一编号体系)里的编号,宽度和 u32 一样。

字符串本体却按 UTF-8 变长编码存:ASCII 字符 1 字节,其他字符 2–4 字节—— 所以 char 和字符串里的字节不是一回事20。

由此得出一个会咬人的事实:.len() 数的是字节,不是字符。

assert_eq!("ಠ_ಠ".len(), 7);        // 7 个字节
assert_eq!("ಠ_ಠ".chars().count(), 3);  // 3 个字符

「ಠ」每个 3 字节、下划线 1 字节,7 = 3+1+321。

再由此得出一个类型学结论:String/&str/char 都是带不变式(invariant)的类型—— 实现层强制遵守的值规则(UTF-8 合法、Unicode 标量(一个独立字符的编号)合法),除了滥用 unsafe 代码外无法破坏, 程序可以放心依赖22。这是「类型即承诺」的第一个实例,后面所有权的论证全靠这类承诺。

从图 2-3 重放:String、&str、str 的内存

书上有张经典插图(图 2-3),把三个概念钉在同一张图上,用语言重放:

let noodles = "noodles".to_string();   // String
let oodles = &noodles[1..];            // &str,借后 6 字节
let disapproodles = "ಠ_ಠ";             // &str,字面量
  • noodles(String):栈上三字段(指针、容量 8、长度 7),指针指着堆上 8 字节的缓冲, 其中 7 个在用。String 是主人;
  • oodles(&str):胖指针——地址 + 长度 6。它指向 noodles 缓冲的内部,不拥有;
  • disapproodles(&str):同样胖指针,但指向程序机器码旁边的只读内存,程序一辈子都在47。

三个名字、三种身份:一个主人、两种借用。所有字符串问题的答案,几乎都能从这张图推出来。

6. 使用与拼写

创建和拼接:

let error_message = "too many pets".to_string();   // &str → String(拷贝)
let place = format!("Hello, {place}!");            // 拼成新 String
let bits = vec!["veni", "vidi", "vici"];
bits.join(", ");                                    // "veni, vidi, vici"

format! 和 println! 同款模板,只是返回字符串不打印;{} 用 Display 格式(给人看), {:?} 用 Debug 格式(给调试看,带引号转义)——元组、切片、Vec、Option 都得用 {:?} 才打印得出来23。

比较与常用方法:== 按内容比(不看地址);contains、replace、trim、split、 starts_with……文档在「Primitive Type str」词条24。 &str 不可改:没有 push,不能按下标赋值——想生成新文本,用 String25。 选型建议(第 4 章详谈):参数优先 &str,和「参数优先切片」同一条逻辑26。

转义序列、原始字符串与 C 串字面量

字符串里的特殊字符用反斜杠转义(text/12 表 2-6)34:

要写的字符 写法
单引号、反斜杠 \'、\\
换行、回车、制表 \n、\r、\t
任意 ASCII \x 加两个十六进制位
任意字符 \u{…} 加至多六个十六进制位

字符串可以跨行,换行和缩进空格都算内容;行尾加一个反斜杠,就能「吃掉」换行和下一行的前导空格, 把长字符串折行排版35。

两个场景让「每个反斜杠写两遍」变成灾难:正则表达式、Windows 路径。 对策是原始字符串:以 r 开头,内容原样收录,不识别任何转义——r"C:\Program Files\Gorillas"。 想内含双引号?给两头加 # 号:r#"…"#,多少个 # 都行,只要内容里没出现同数量的 "#36。

b"…" 是字节串(类型 &[u8; N],内容不要求是合法 UTF-8——b"\x7fELF" 是几乎每个 Linux 可执行文件开头的魔数);c"…" 是 C 串(零结尾,类型 &CStr,为对接 C API 准备)37。

拼接与格式化

造字符串的三件套:to_string() 拷贝一份、format! 按模板拼、concat/join 连列表。 格式串里 {} 是 Display 格式(给人看),{:?} 是 Debug 格式(给调试看:字符串带引号、 特殊字符转义)。不是所有类型都支持 Display,但几乎所有类型都支持 Debug—— 想打印元组、切片、Vec、Option,只有 {:?} 这一条路38。

字符串比较按内容不按地址:"ONE".to_lowercase() == "one" 成立。 常用方法一带而过:contains、replace、trim、split、字符的 is_alphabetic、 to_digit……文档都在「Primitive Type str / char」词条下39。

7. 其他「像字符串的类型」和字节串

Rust 保证字符串是合法 UTF-8,但操作系统不保证(文件名、环境变量(操作系统传给程序的一批键值对)可以是任意字节)。 对策是一排特化类型,按场景换用27:

场景 用
普通文本 String / &str
文件名 PathBuf / &Path
环境变量、命令行参数(可能是非 UTF-8) OsString / OsStr
根本不是文本的二进制 Vec<u8> / &[u8]
和 C 库互操作(零结尾串) CString / CStr

两种特殊字面量:b"…" 是字节串(类型 &[u8; N],不需要合法 UTF-8—— b"\x7fELF" 就是几乎每个 Linux 可执行文件开头的那 4 个魔数字节); c"…" 是 C 串(零结尾,类型 &CStr)28。

收尾一个轻量特性:type 关键字给已有类型起别名(对标 C++ 的 typedef): type Bytes = Vec<u8>;——新名字,不是新类型29。

表 2-1 的用法:一张总览当字典

原书第 2 章开头有一张「全书类型总览表」(表 2-1),性质是字典不是课文: 每种类型一行,给名字、一句话描述、一个值的样子。把它当回查表用,遇到没见过的类型先在这里对号入座40:

类型 一句话 值的样子
i8…i128 / u8…u128 定宽整数 42、-5i8、0x400u16
isize / usize 机器字长整数 137、下标、长度
f32 / f64 IEEE 浮点 1.0、6.0221e23
bool 布尔 true、false
(char, u8, i32) 元组 ('%', 0x7f, -1)
() 单元 ()
struct S 具名字段结构体 S { x: 120.0, y: 209.0 }
struct T(i32, char) 元组式结构体 T(120, 'X')
struct E; 单元式结构体 E
enum Attend 枚举 Attend::Late(5)
Box<T> 堆上独占指针 Box::new(v)
&T / &mut T 共享 / 可变引用 &s.y、&mut v
String 堆上 UTF-8 文本 "…".to_string()
&str 借来的 UTF-8 文本 "…"、&s[0..12]
char Unicode 字符 '字'、'\n'、'\u{CA0}'
[f64; 4] 定长数组 [1.0, 0.0, 0.0, 1.0]
Vec<f64> 可增长向量 vec![0.367, 2.718]
&[u8] / &mut [u8] 切片引用 &v[10..20]
Option<&str> 可选值 Some("Dr.")、None
Result<u64, Error> 可失败的结果 Ok(4096)、Err(…)
&dyn Error 等 trait 对象引用 &err as &dyn Error
fn(&str) -> bool 函数指针 str::is_empty
闭包 (无书面类型) \|a, b\| { a*a + b*b }

表里的大多数本章已讲;struct/enum/trait 对象/闭包各有专章——总览表的价值在于: 今天读到这里,回查一下「这个类型站在哪一层」。

容量与长度:一个看得见的实验

len 是现在装几个,capacity 是最多不用搬家能装几个。书上的实验41:

let mut v = Vec::with_capacity(2);
assert_eq!(v.len(), 0);
assert_eq!(v.capacity(), 2);
v.push(1); v.push(2);          // 正好装满,不搬家
assert_eq!(v.len(), 2);
assert_eq!(v.capacity(), 2);
v.push(3);                      // 装不下了:换大缓冲
assert_eq!(v.len(), 3);
// 通常打印 "capacity is now 4":
println!("capacity is now {}", v.capacity());

容量变 4 不保证(只保证 ≥3)——增长策略是实现细节。这个「不保证」本身也是教材: 依赖未承诺的行为,是 C 的老毛病;读 len/capacity 的值做决策,而不是猜实现42。

中间插入与删除:快的假象与真的代价

insert 和 remove 都收得下标,但书上的提醒很直白:它们会把受影响位置之后的 所有元素整体搬一次家——在长的向量中间插一个,后面一百万个元素各挪一格。 短向量无感,长向量是性能事故。常用的尾部操作(push/pop)才是不搬家的那档43。

UTF-8 一句话版(补充,不在书里的展开)

书里只给了结论:ASCII 字符 1 字节,其他字符 2–4 字节。展开一句方便建立直觉: UTF-8 是一种「编号小的字符省空间」的编码——常用的英文字母、数字一个字节, 汉字、日文通常三个,「emoji」四个。一份以英文为主的日志,UTF-8 存储几乎不花额外空间, 这就是它取代定宽编码统治了万维网的原因(补充,不在书里,来自通用知识)。 Rust 选 UTF-8 作字符串本体,等于免费继承了这个生态44。

由此而来的两个使用纪律:其一,len() 数字节,判长度想数字符就用 .chars().count(); 其二,按下标或区间切字符串可能切在字符中间(那 7 个字节的 "ಠ_ಠ" 切成前 4 字节就不成字符), Rust 对字符串切片按字符边界检查,切歪了 panic——原书把细节留给了字符串专章, 这里只需记住「字符串的下标是字节,不是字符」45。

&str 还是 String:参数选型的一句话

函数参数优先 &str——它和「参数优先切片而非向量」是同一个道理: &str 能指向字面量、能指向 String、能指向任何字符串的一段,String 只指向自己拥有的那份。 调用方不用为你多拷贝一次,接口也宽。什么时候真的需要 String? 函数要存下这段文本、或要把它改长改短的时候——那就连所有权一起收进来46。

8. 作者的判断与证据

  • 「函数该收切片引用」是原书明确推荐的工程惯例,理由是泛用性——证据是 sort/reverse 定义在切片上这个既成事实15。
  • 「len 按字节」是 UTF-8 决定的客观事实,不是设计口味;原书用 ಠ_ಠ 的例子把它钉死21。
  • 「类型带不变式」是 Rust 安全论证的地基性主张:unsafe 之外无法破坏——这是语言承诺22。

9. 边界与局限

  • UTF-8 的编码细节(代理对、组合字符)原书没展开;按字节数切片可能在字符中间切断, 这个坑原书留在字符串专章([Link to Come]);
  • PathBuf/OsString/CString 只给了选型表,用法没有示例;
  • Vec 的高级方法、collect 的机制都指向未放出的章节。

10. 可带走的

主线例子一行版: vec![0; 1200 万] 建缓冲 → &mut [u8] 借给 render 写入 → chunks_mut 切成条带 → &[u8] 只读借给 write_image。

  1. 数组定长、长度是类型的一部分;运行时定长用 Vec;
  2. 没有未初始化数组——Rust 保证你碰不到未初始化的值;
  3. 下标越界 panic(不是 undefined behavior),下标必须是 usize;
  4. Vec = 指针 + 容量 + 长度三个机器字;容量满则换新缓冲拷贝;
  5. 切片引用是胖指针:地址 + 长度;数组、向量自动降级成切片;
  6. 函数参数能收 &[T] 就别收 &Vec<T>——sort/reverse 定义在切片上就是这个道理;
  7. String 类比 Vec<u8>(保证 UTF-8),&str 类比 &u8;
  8. len() 数字节不数字符:"ಠ_ಠ".len() 是 7,.chars().count() 是 3;
  9. char 恒 4 字节(Unicode 标量),字符串本体按 UTF-8 变长存储;
  10. 非 UTF-8 场景有专门的类型:文件名 PathBuf、命令行 OsString、二进制 Vec<u8>、C 串 CString。

11. 原文地图

主题 原书章 原文位置
三种序列类型总览 Chapter 2. Fundamental Types text/12-ch02-chapter-2-fundamental-types.txt:525(搜「fixed-size array」)
无未初始化数组 Chapter 2. Fundamental Types text/12-ch02-chapter-2-fundamental-types.txt:559(搜「uninitialized array」)
下标检查与 usize Chapter 2. Fundamental Types text/12-ch02-chapter-2-fundamental-types.txt:531(搜「panics」)
Vec 三机器字与扩容 Chapter 2. Fundamental Types text/12-ch02-chapter-2-fundamental-types.txt:620(搜「three values」)
with_capacity 与 collect Chapter 2. Fundamental Types text/12-ch02-chapter-2-fundamental-types.txt:622(搜「with_capacity」)
insert/remove/pop Chapter 2. Fundamental Types text/12-ch02-chapter-2-fundamental-types.txt:644(搜「insert」) · text/12-ch02-chapter-2-fundamental-types.txt:656(搜「pop」)
切片与胖指针 Chapter 2. Fundamental Types text/12-ch02-chapter-2-fundamental-types.txt:699(搜「fat pointer」)
参数该收切片 Chapter 2. Fundamental Types text/12-ch02-chapter-2-fundamental-types.txt:734(搜「slice references rather than」)
String/&str 类比 Vec/&[T] Chapter 2. Fundamental Types text/12-ch02-chapter-2-fundamental-types.txt:850(搜「analogous to」)
内存布局与不变式 Chapter 2. Fundamental Types text/12-ch02-chapter-2-fundamental-types.txt:825(搜「resizable buffer」) · text/12-ch02-chapter-2-fundamental-types.txt:829(搜「invariants」)
len 数字节 Chapter 2. Fundamental Types text/12-ch02-chapter-2-fundamental-types.txt:835(搜「bytes, not characters」)
字符串字面量住只读内存 Chapter 2. Fundamental Types text/12-ch02-chapter-2-fundamental-types.txt:833(搜「read-only memory」)
其他字符串类型选型 Chapter 2. Fundamental Types text/12-ch02-chapter-2-fundamental-types.txt:957(搜「PathBuf」)
字节串与 C 串字面量 Chapter 2. Fundamental Types text/12-ch02-chapter-2-fundamental-types.txt:973(搜「byte string」) · text/12-ch02-chapter-2-fundamental-types.txt:977(搜「null-terminated」)
素数筛与数组语法 Chapter 2. Fundamental Types text/12-ch02-chapter-2-fundamental-types.txt:545(搜「sieve」)
proglangs 分类例子 Chapter 2. Fundamental Types text/12-ch02-chapter-2-fundamental-types.txt:671(搜「functional」)
转义序列与原始字符串 Chapter 2. Fundamental Types text/12-ch02-chapter-2-fundamental-types.txt:767(搜「escape sequences」) · text/12-ch02-chapter-2-fundamental-types.txt:797(搜「raw string」)
拼接与格式化 Chapter 2. Fundamental Types text/12-ch02-chapter-2-fundamental-types.txt:902(搜「format specifier」)
表 2-1 类型总览 Chapter 2. Fundamental Types text/12-ch02-chapter-2-fundamental-types.txt:41(搜「Table 2-1」)
容量与长度实验 Chapter 2. Fundamental Types text/12-ch02-chapter-2-fundamental-types.txt:639(搜「capacity is now」)
插删的搬家成本 Chapter 2. Fundamental Types text/12-ch02-chapter-2-fundamental-types.txt:644(搜「shift all the elements」)
&str 还是 String Chapter 2. Fundamental Types text/12-ch02-chapter-2-fundamental-types.txt:923(搜「preferable to String」)
图 2-3 内存布局重放 Chapter 2. Fundamental Types text/12-ch02-chapter-2-fundamental-types.txt:821(搜「noodles」)
type 别名 Chapter 2. Fundamental Types text/12-ch02-chapter-2-fundamental-types.txt:983(搜「typedef」)

  1. 出处:「Chapter 2. Fundamental Types」第 525–527 段(text/12-ch02-chapter-2-fundamental-types.txt:525-527,搜「fixed-size array」)。 ↩

  2. 出处:「Chapter 2. Fundamental Types」第 559 段(text/12-ch02-chapter-2-fundamental-types.txt:559,搜「uninitialized array」)。 ↩

  3. 出处:「Chapter 2. Fundamental Types」第 531 段(text/12-ch02-chapter-2-fundamental-types.txt:531,搜「panics」)。 ↩

  4. 出处:「Chapter 2. Fundamental Types」第 531 段(text/12-ch02-chapter-2-fundamental-types.txt:531,搜「usize value」)。 ↩

  5. 出处:「Chapter 2. Fundamental Types」第 561 段(text/12-ch02-chapter-2-fundamental-types.txt:561,搜「use a vector instead」)。 ↩

  6. 出处:「Chapter 2. Fundamental Types」第 575–606 段(text/12-ch02-chapter-2-fundamental-types.txt:575-606,搜「vec! macro」)。 ↩

  7. 出处:「Chapter 2. Fundamental Types」第 620 段(text/12-ch02-chapter-2-fundamental-types.txt:620,搜「three values」)。 ↩

  8. 出处:「Chapter 2. Fundamental Types」第 622–624 段(text/12-ch02-chapter-2-fundamental-types.txt:622-624,搜「pre-allocate」)。 ↩

  9. 出处:「Chapter 2. Fundamental Types」第 626–642 段(text/12-ch02-chapter-2-fundamental-types.txt:626-642,搜「capacity is now」)。 ↩

  10. 出处:「Chapter 2. Fundamental Types」第 644–661 段(text/12-ch02-chapter-2-fundamental-types.txt:644-661,搜「Option<T>」)。 ↩

  11. 出处:「Chapter 2. Fundamental Types」第 697–699 段(text/12-ch02-chapter-2-fundamental-types.txt:697-699,搜「always passed by reference」)。 ↩

  12. 出处:「Chapter 2. Fundamental Types」第 699 段(text/12-ch02-chapter-2-fundamental-types.txt:699,搜「fat pointer」)。 ↩

  13. 出处:「Chapter 2. Fundamental Types」第 715–730 段(text/12-ch02-chapter-2-fundamental-types.txt:715-730,搜「range」)。 ↩

  14. 出处:「Chapter 2. Fundamental Types」第 563–569 段(text/12-ch02-chapter-2-fundamental-types.txt:563-569,搜「implicitly converts」)。 ↩

  15. 出处:「Chapter 2. Fundamental Types」第 734 段(text/12-ch02-chapter-2-fundamental-types.txt:734,搜「slice references rather than」)。 ↩↩

  16. render 的切片参数见「Plotting the Set」第 32 段(text/08-fm-plotting-the-set.txt:32,搜「mutable reference」);write_image 见「Writing Image Files」第 11–15 段(text/09-fm-writing-image-files.txt:11-15,搜「pixels: &[u8]」)。 ↩

  17. 出处:「Chapter 2. Fundamental Types」第 850 段(text/12-ch02-chapter-2-fundamental-types.txt:850,搜「analogous to」)。 ↩

  18. 出处:「Chapter 2. Fundamental Types」第 825–827 段(text/12-ch02-chapter-2-fundamental-types.txt:825-827,搜「resizable buffer」)。 ↩

  19. 出处:「Chapter 2. Fundamental Types」第 833 段(text/12-ch02-chapter-2-fundamental-types.txt:833,搜「read-only memory」)。 ↩

  20. 出处:「Chapter 2. Fundamental Types」第 815–817 段(text/12-ch02-chapter-2-fundamental-types.txt:815-817,搜「variable-width encoding」)。 ↩

  21. 出处:「Chapter 2. Fundamental Types」第 835–838 段(text/12-ch02-chapter-2-fundamental-types.txt:835-838,搜「bytes, not characters」)。 ↩↩

  22. 出处:「Chapter 2. Fundamental Types」第 829 段(text/12-ch02-chapter-2-fundamental-types.txt:829,搜「invariants」)。 ↩↩

  23. 出处:「Chapter 2. Fundamental Types」第 897–913 段(text/12-ch02-chapter-2-fundamental-types.txt:897-913,搜「format specifier」)。 ↩

  24. 出处:「Chapter 2. Fundamental Types」第 927–939 段(text/12-ch02-chapter-2-fundamental-types.txt:927-939,搜「contains」)。 ↩

  25. 出处:「Chapter 2. Fundamental Types」第 840–846 段(text/12-ch02-chapter-2-fundamental-types.txt:840-846,搜「impossible to modify」)。 ↩

  26. 出处:「Chapter 2. Fundamental Types」第 923 段(text/12-ch02-chapter-2-fundamental-types.txt:923,搜「preferable to String」)。 ↩

  27. 出处:「Chapter 2. Fundamental Types」第 951–963 段(text/12-ch02-chapter-2-fundamental-types.txt:951-963,搜「PathBuf」)。 ↩

  28. 出处:「Chapter 2. Fundamental Types」第 967–977 段(text/12-ch02-chapter-2-fundamental-types.txt:967-977,搜「byte string」与「null-terminated」)。 ↩

  29. 出处:「Chapter 2. Fundamental Types」第 983–991 段(text/12-ch02-chapter-2-fundamental-types.txt:983-991,搜「typedef」)。 ↩

  30. 出处:「Chapter 2. Fundamental Types」第 543–557 段(text/12-ch02-chapter-2-fundamental-types.txt:543-557,搜「lazy_caterer」)。 ↩

  31. 出处:「Chapter 2. Fundamental Types」第 663–691 段(text/12-ch02-chapter-2-fundamental-types.txt:663-691,搜「error_messages」)。 ↩

  32. 出处:「Chapter 2. Fundamental Types」第 726–732 段(text/12-ch02-chapter-2-fundamental-types.txt:726-732,搜「extends past the end」)。 ↩

  33. 出处:「Chapter 2. Fundamental Types」第 734 段(text/12-ch02-chapter-2-fundamental-types.txt:734,搜「for generality」)。 ↩

  34. 出处:「Chapter 2. Fundamental Types」第 767–795 段(text/12-ch02-chapter-2-fundamental-types.txt:767-795,搜「escape sequences」)。 ↩

  35. 出处:「Chapter 2. Fundamental Types」第 752–765 段(text/12-ch02-chapter-2-fundamental-types.txt:752-765,搜「backslash」)。 ↩

  36. 出处:「Chapter 2. Fundamental Types」第 797–811 段(text/12-ch02-chapter-2-fundamental-types.txt:797-811,搜「raw string」)。 ↩

  37. 出处:「Chapter 2. Fundamental Types」第 967–977 段(text/12-ch02-chapter-2-fundamental-types.txt:967-977,搜「byte string」)。 ↩

  38. 出处:「Chapter 2. Fundamental Types」第 897–913 段(text/12-ch02-chapter-2-fundamental-types.txt:897-913,搜「Display」)。 ↩

  39. 出处:「Chapter 2. Fundamental Types」第 925–947 段(text/12-ch02-chapter-2-fundamental-types.txt:925-947,搜「contains」)。 ↩

  40. 出处:「Chapter 2. Fundamental Types」第 41–165 段(text/12-ch02-chapter-2-fundamental-types.txt:41-165,搜「Table 2-1」)。表中各行的描述与值示例取自该表。 ↩

  41. 出处:「Chapter 2. Fundamental Types」第 626–642 段(text/12-ch02-chapter-2-fundamental-types.txt:626-642,搜「capacity is now」)。 ↩

  42. 出处:「Chapter 2. Fundamental Types」第 642 段(text/12-ch02-chapter-2-fundamental-types.txt:642,搜「isn't guaranteed」)。 ↩

  43. 出处:「Chapter 2. Fundamental Types」第 644–652 段(text/12-ch02-chapter-2-fundamental-types.txt:644-652,搜「shift all the elements」)。 ↩

  44. 补充(不在书里,来自通用知识):UTF-8 是变长编码,常用字符省字节;Rust 字符串底层即 UTF-8 见「Chapter 2. Fundamental Types」第 817 段(text/12-ch02-chapter-2-fundamental-types.txt:817,搜「variable-width」)。 ↩

  45. 出处:「Chapter 2. Fundamental Types」第 835–838 段(text/12-ch02-chapter-2-fundamental-types.txt:835-838,搜「bytes, not characters」)。 ↩

  46. 出处:「Chapter 2. Fundamental Types」第 923 段(text/12-ch02-chapter-2-fundamental-types.txt:923,搜「preferable to String」)。 ↩

  47. 出处:「Chapter 2. Fundamental Types」第 819–833 段(text/12-ch02-chapter-2-fundamental-types.txt:819-833,搜「Figure 2-3」)。 ↩