调用、运算符与类型转换 — 表达式(下)¶
这一章是语法手册式的收尾: 函数和方法怎么调、字段和切片怎么取、 运算符里哪些是 C 的老样子、哪些悄悄改了规则。没有大的理论, 但每一条「与 C 不同」背后都有一次踩坑史。
1. 顶层全景:从大到小¶
调用:函数 gcd(a,b) / 方法 v.sort() / 类型关联函数 Vec::new()
│
▼
取值:字段 point.x · 元组字段 t.0 · 下标 v[i] · 切片 &v[a..b]
│
▼
运算与转换:算术/位/比较/逻辑 · 赋值与复合赋值 · as · deref 强转
图说:. 号和 [] 号都会自动解引用——「指到第几层」不用你数。
本章的主线例子是快排的两个递归(函数自己调自己)切片:quicksort(&mut slice[..pivot_index]) 和
quicksort(&mut slice[pivot_index + 1..])——区间切片、可变借用加递归,三个语法点一步全走完。
2. 三种调用形态与一个语法怪癖¶
- 函数调用:
gcd(1302, 462)。 - 方法调用:
player.location()。.号照例自动解引用:player是Player、&Player、Box<Player>还是Rc<Player>,.location()都能调——方法按值收、按引用收,匹配自动完成1。 - 类型关联函数:
Vec::new()——不是挂在一个值上,而是挂在类型上(对标 OOP 的静态方法)2。 链式调用随便串(第一章的.bind(...).expect(...).run().expect(...))。
turbofish:在表达式里给泛型函数显式喂类型参数,不能写 Vec<T> 的尖括号——
因为表达式里 < 是小于号,Vec<i32>::with_capacity(1000) 会被当成一链比较。
解法是加一对尖括号前导 :::Vec::<i32>::with_capacity(1000)、(0..n).collect::<Vec<i32>>()。
这个记号 ::<...> 在社区里的昵称就是 turbofish(涡轮鱼)3。
多数时候能省:返回类型或变量类型会兜住推断,能省就省是良好风格4。
链式调用为什么能链¶
第 1 章 web 服务器里那一长串 .bind(...).expect(...).run().expect(...) 能成立,
是因为这些方法的返回值又是带方法的对象,接着调即可。它不是语法特性,只是
「返回值设计」的副产品——配合「块/表达式的值」的规则,每个 .xxx() 既做事又交出下一个对象30。
字段、下标与 lvalue¶
能出现在赋值号左边的叫 lvalue(C 的老术语),Rust 里有三类:
game.black_pawns = 0x00ff0000_00000000_u64; // 结构体字段
coords.1 = 0; // 元组字段(按编号)
pieces[2] = Some(Piece::new(Black, Knight, coords)); // 数组/切片/向量元素
左边是引用或智能指针时自动解引用,和赋值无关的地方一样;当然,容器本身必须是 mut 的,
否则连字段都改不了。切片取值与赋值同一套下标:&game_moves[midpoint..end] 借一段,
v[a..b] 的形态共六种,边界照旧检查31。
3. 字段、下标、切片区间¶
结构体字段 point.x、元组字段 pair.0、数组/切片/向量元素 pieces[i]——
左边是引用或智能指针时自动解引用;这三类表达式可以出现在赋值号左边(此时要求容器本身是 mut 的)5。
区间切片:&v[a..b] 借出从下标 a 到 b(不含 b)的一段;两端都可以省略。
.. 按两端有无产出四种类型(RangeFull、RangeFrom、RangeTo、Range),
..= 再产出两种闭区间类型;只有带起点的区间能拿来 for 循环(循环得有个起点),
但六种形态在切片里全有用6。
回到主线例子,原书用快排展示切片在递归里的样子:
fn quicksort<T: Ord>(slice: &mut [T]) {
if slice.len() <= 1 { return; }
let pivot_index = partition(slice);
quicksort(&mut slice[.. pivot_index]); // 前一半:起点省略
quicksort(&mut slice[pivot_index + 1 ..]); // 后一半:终点省略
}
一次调用借出前半的可变切片,递归排完;再借出后半——两个借用前后错开、从不重叠,
所以每次都安全。泛型参数 <T: Ord>(只对可排序的类型)这里先当背景,细节在未放出的章节7。
区间类型速查¶
.. 按两端有无产出四种类型;..= 再补两种闭区间。只有带起点的两种能 for 循环
(循环总得从哪开始),六种形态在切片里全有用32:
| 写法 | 类型 | 含起点 | 含终点 | 能 for |
|---|---|---|---|---|
.. |
RangeFull | — | — | 否(切片专用) |
a.. |
RangeFrom | 是 | 到尾 | 是 |
..b |
RangeTo | 从头 | 否 | 否 |
a..b |
Range | 是 | 否 | 是 |
..=b |
RangeToInclusive | 从头 | 是 | 否 |
a..=b |
RangeInclusive | 是 | 是 | 是 |
「含不含终点」的记忆口诀:两点的 .. 不含(0..3 是 0、1、2),
带等号的 ..= 含(0..=3 是 0、1、2、3)。切片里省略端点就默认顶到数据的头或尾。
链式调用的完整样本¶
第 1 章服务器的那段链值得再看一眼——它把「每步返回值都是下一个方法的接收者」 用到了实处33:
server
.bind("127.0.0.1:3000").expect("error binding server to address")
.run().expect("error running server");
bind 返回绑定好的 server,run 在它身上启动;两个 expect 各管一步的错误。
链式不是炫技,是「中间结果没有名字、也不需要名字」的诚实写法。
4. 算术、位、比较:和 C 分手的细节¶
大体是熟面孔,不同处才是考点:
- 整数除法向零取整;整数除以零在 release 也 panic。
不想 panic 用
a.checked_div(b),返回Option(除零时是None)8。 %取余对浮点也有效:1234.567 % 10.0 ≈ 4.567;结果符号跟左操作数9。- 没有一元
+;一元-不支持无符号数(-100u32报错)10。 - 位取反用
!不是~:所以!n不能当「n 是零」用,得写n == 011。 - 位移:有符号数恒符号扩展,无符号数恒零扩展——因为有明确的unsigned类型,
Java 那个
>>>(强制零扩展)在 Rust 里没必要存在12。 - 位运算优先级高于比较:
x & BIT != 0是(x & BIT) != 0——「正如你本意」; C 里是x & (BIT != 0),测的是错误的那个比特13。 - 比较的两个操作数必须同类型;
&&、||短路,操作数必须 bool14。 - 没有
++/--15。
赋值:= 给 mut 变量(及其字段/元素)赋值;非 Copy 类型赋值即移动(第 3 章)。
复合赋值(+= 等)齐;不支持链式赋值(a = b = 3 不行),不支持逗号表达式。
原书的解释很 Rust:赋值本来就罕见(变量默认不可变),这些捷径用不上16。
一元 *:什么时候真要写¶
Rust 的 . 号替你解引用,所以 * 的戏份比 C 少,但有一幕非它不可:
你要的是整个值,不是某个字段或方法。
let padovan: Vec<u64> = compute_padovan_sequence(n);
for elem in &padovan {
draw_triangle(turtle, *elem); // draw_triangle 要 u64,elem 是 &u64
}
elem 的类型是 &u64,函数要 u64——*elem 把「整个所指值」取出来22。
取字段(elem.x)和调方法(elem.len())有 . 号代劳,取整个值只能自己动手。
位运算与 C 的分手清单¶
把 Rust 从 C 的位运算习惯里带出来的差异收拢成一张表23:
| 主题 | C | Rust |
|---|---|---|
| 按位取反 | ~n |
!n |
!n 的额外含义 |
可当「n 为假」用 | 只能作用于 bool——想判断整数零,写 n == 0 |
| 位移扩展 | 有符号行为实现相关;Java 要 >>> 补零 |
有符号恒符号扩展,无符号恒零扩展,无需第三运算符 |
x & BIT != 0 |
解析成 x & (BIT != 0),测错比特 |
位运算优先于比较,解析成 (x & BIT) != 0 |
% 取余 |
整数专属 | 浮点也行,符号跟左操作数 |
最后一条的例子:1234.567 % 10.0 约等于 4.56724。
赋值与复合赋值¶
= 给 mut 变量、字段、元素赋值;非 Copy 类型赋值即移动,目标原来的值先被丢弃
(第 3 章)。复合赋值(+= 等)是一组完整操作:total += item.price 就是
total = total + item.price25。
三个「没有」:没有链式赋值(a = b = 3 不行)、没有 ++/--、
没有逗号表达式。原书的解释透着 Rust 的脾气:变量默认不可变,赋值本来就罕见,
这些捷径没了就没了26。
5. as 转换:谁可以、谁禁止¶
转换的写法是 as。完整规则一张表17:
| 从 → 到 | 规则 |
|---|---|
| 数值 ↔ 数值 | 总是定义良好。变窄截断;有符号变宽符号扩展、无符号零扩展;浮点→整数向零取整,太大则夹到类型边界(1e6 as u8 是 255) |
| bool/char/类 C 枚举 → 整数 | 可以 |
| 整数 → bool/char/枚举 | 禁止。方向反过来需要运行时检查(如 u16 可能是代理区 0xd800,不是合法字符);要用就调 std::char::from_u32 拿 Option<char> |
| u8 → char | 唯一例外:0–255 全是合法码点 |
| 部分裸指针互转 | 允许(需 unsafe 配合) |
「禁止反向转换」的逻辑和溢出四族操作一脉相承:会静默出错的转换要么显式查、要么不许写18。
deref 强转(deref coercion):几种引用之间的转换自动发生、不用 as——
&String 自动转 &str,&Vec<i32> 自动转 &[i32],&Box<Chessboard> 自动转 &Chessboard。
它们适用于实现了 Deref trait 的类型,目的是让智能指针用起来尽量像底层值本身19。
自己写智能指针类型时也能实现 Deref(方法在未放出章节)。
6. 闭包:一句带过的大坑¶
闭包是轻量的「函数一样的值」:竖线里是参数,后面是表达式;参数类型和返回类型都能推断 (写返回类型时,体必须用大括号)20。调用语法和普通函数一样。 「Rust 闭包里最可喜的特性」——原书原话——这里卖了个关子,整章留给后面21。
deref 强转:智能指针「装成本体」的原理¶
&String → &str、&Vec<i32> → &[i32]、&Box<Chessboard> → &Chessboard,
这三种转换自动发生、不用 as,合称 deref 强转。背后的机制:这些类型都实现了
Deref 这个内建 trait,转换规则写在实现里27。
设计意图一句话:让智能指针用起来尽量像本体。Box<Chessboard> 基本上就是
一个 Chessboard——能传进任何收 &Chessboard 的函数,能直接调它的方法——
靠的就是 deref 强转把「指针的外衣」悄悄脱了28。自己写智能指针类型时也能实现
Deref(方法在未放出章节)。
闭包写法的完整规则¶
let is_even = |x| x % 2 == 0; // 参数类型、返回类型都推断
assert_eq!(is_even(14), true); // 调用语法和普通函数一样
let is_even = |x: u64| -> bool { x % 2 == 0 }; // 显式写出:体必须用大括号
两条规矩:竖线里是参数;一旦显式声明返回类型,体必须是 { … } 块——
这是语法健全性的小妥协,记住即可29。闭包的捕获、三种闭包 trait、
把闭包存进结构体,全是后面章节的内容,本章只交付「能读、能写、能调」。
7. 作者的判断与证据¶
- 「位运算优先于比较」比 C 更有用是明确的判断,附带对 C 的吐槽(测错比特)13;
- 「没有链式赋值、没有 ++/--,你不会想念它们」建立在「赋值罕见」的前提上—— 这个前提来自「变量默认不可变」,链条完整,是论证不是口味16;
- turbofish 的由来是语法冲突的客观结果(表达式里
<已被小于号占用)3。
8. 边界与局限¶
as里裸指针的转换只给了一句,unsafe 章节才展开;- 运算符重载(给自定义类型实现
+)本章没讲; - 闭包的捕获规则、三种闭包 trait(Fn/FnMut/FnOnce)整个缺席;
- 区间类型在迭代器上下文(
(a..b).step_by(2))的用法留给后面章节。
9. 可带走的¶
主线例子一行版: quicksort(&mut slice[..p]) → 借前半可变切片递归 → 前后两个借用错开不重叠 → 合法。
- 三种调用:函数、方法(. 自动解引用)、类型关联函数(
Vec::new); - 表达式里给泛型喂类型用
::<T>(turbofish),能推断就省略; - 切片区间六种形态,递归分治的借力点;
- 整数除零 panic(任何构建);不想 panic 用 checked_div;
%可用于浮点;位取反是!;- 位运算优先级高于比较(Rust)——
x & BIT != 0就是你想的那个; - 无
++/--、无链式赋值、无一元+; as:数值互转总合法;整数→char 禁止(代理区),u8→char 例外;反向都要检查;- deref 强转:
&String→&str、&Vec<T>→&[T]自动发生; - 闭包
|x| 表达式,类型可推断,大篇内容在后面。
10. 原文地图¶
| 主题 | 原书章 | 原文位置 |
|---|---|---|
| 三种调用形态 | Chapter 5. Expressions | text/15-ch05-chapter-5-expressions.txt:739(搜「location」) · text/15-ch05-chapter-5-expressions.txt:745(搜「type-associated」) |
| . 号自动解引用/借 | Chapter 5. Expressions | text/15-ch05-chapter-5-expressions.txt:743(搜「relaxes」) |
| turbofish | Chapter 5. Expressions | text/15-ch05-chapter-5-expressions.txt:760(搜「chained comparisons」) · text/15-ch05-chapter-5-expressions.txt:770(搜「turbofish」) |
| 字段/下标/lvalue | Chapter 5. Expressions | text/15-ch05-chapter-5-expressions.txt:795(搜「lvalues」) |
| 区间六种形态 | Chapter 5. Expressions | text/15-ch05-chapter-5-expressions.txt:811(搜「RangeFull」) |
| 快排例子 | Chapter 5. Expressions | text/15-ch05-chapter-5-expressions.txt:827(搜「quicksort」) |
| 整除/除零/checked_div | Chapter 5. Expressions | text/15-ch05-chapter-5-expressions.txt:865(搜「rounds toward zero」) |
| 无一元 + | Chapter 5. Expressions | text/15-ch05-chapter-5-expressions.txt:871(搜「leading +」) |
| 取余与位取反 | Chapter 5. Expressions | text/15-ch05-chapter-5-expressions.txt:873(搜「modulus」) · text/15-ch05-chapter-5-expressions.txt:877(搜「bitwise NOT」) |
| 位移扩展规则 | Chapter 5. Expressions | text/15-ch05-chapter-5-expressions.txt:884(搜「sign-extending」) |
| 位运算优先级 | Chapter 5. Expressions | text/15-ch05-chapter-5-expressions.txt:886(搜「higher precedence」) |
| 无 ++/--、无链式赋值 | Chapter 5. Expressions | text/15-ch05-chapter-5-expressions.txt:906(搜「increment and decrement」) · text/15-ch05-chapter-5-expressions.txt:904(搜「chaining」) |
| as 转换规则 | Chapter 5. Expressions | text/15-ch05-chapter-5-expressions.txt:910(搜「as keyword」) · text/15-ch05-chapter-5-expressions.txt:921(搜「rounds toward zero」) · text/15-ch05-chapter-5-expressions.txt:925(搜「surrogate」) |
| deref 强转 | Chapter 5. Expressions | text/15-ch05-chapter-5-expressions.txt:935(搜「auto-convert」) · text/15-ch05-chapter-5-expressions.txt:941(搜「deref coercions」) |
| 一元 * 与整个值 | Chapter 5. Expressions | text/15-ch05-chapter-5-expressions.txt:850(搜「underlying values」) |
| 位运算与 C 的分手清单 | Chapter 5. Expressions | text/15-ch05-chapter-5-expressions.txt:877(搜「bitwise NOT」) |
| deref 强转 | Chapter 5. Expressions | text/15-ch05-chapter-5-expressions.txt:935(搜「auto-convert」) |
| 闭包写法规则 | Chapter 5. Expressions | text/15-ch05-chapter-5-expressions.txt:947(搜「vertical bars」) |
| 链式调用与 lvalue | Chapter 5. Expressions | text/15-ch05-chapter-5-expressions.txt:751(搜「chained」) · text/15-ch05-chapter-5-expressions.txt:795(搜「lvalues」) |
| 区间类型速查 | Chapter 5. Expressions | text/15-ch05-chapter-5-expressions.txt:811(搜「RangeFull」) |
| 闭包入门 | Chapter 5. Expressions | text/15-ch05-chapter-5-expressions.txt:947(搜「lightweight」) |
-
出处:「Chapter 5. Expressions」第 743 段(
text/15-ch05-chapter-5-expressions.txt:743,搜「relaxes」)。 ↩ -
出处:「Chapter 5. Expressions」第 745–749 段(
text/15-ch05-chapter-5-expressions.txt:745-749,搜「static methods」)。 ↩ -
出处:「Chapter 5. Expressions」第 758–770 段(
text/15-ch05-chapter-5-expressions.txt:758-770,搜「chained comparisons」与「turbofish」)。 ↩↩ -
出处:「Chapter 5. Expressions」第 772–778 段(
text/15-ch05-chapter-5-expressions.txt:772-778,搜「good style」)。 ↩ -
出处:「Chapter 5. Expressions」第 780–801 段(
text/15-ch05-chapter-5-expressions.txt:780-801,搜「lvalues」)。 ↩ -
出处:「Chapter 5. Expressions」第 809–825 段(
text/15-ch05-chapter-5-expressions.txt:809-825,搜「RangeFull」)。 ↩ -
出处:「Chapter 5. Expressions」第 827–842 段(
text/15-ch05-chapter-5-expressions.txt:827-842,搜「quicksort」)。 ↩ -
出处:「Chapter 5. Expressions」第 863–865 段(
text/15-ch05-chapter-5-expressions.txt:863-865,搜「rounds toward zero」)。 ↩ -
出处:「Chapter 5. Expressions」第 873–875 段(
text/15-ch05-chapter-5-expressions.txt:873-875,搜「modulus」)。 ↩ -
出处:「Chapter 5. Expressions」第 867–871 段(
text/15-ch05-chapter-5-expressions.txt:867-871,搜「leading+」)。 ↩ -
出处:「Chapter 5. Expressions」第 877–882 段(
text/15-ch05-chapter-5-expressions.txt:877-882,搜「bitwise NOT」)。 ↩ -
出处:「Chapter 5. Expressions」第 884 段(
text/15-ch05-chapter-5-expressions.txt:884,搜「sign-extending」)。 ↩ -
出处:「Chapter 5. Expressions」第 886 段(
text/15-ch05-chapter-5-expressions.txt:886,搜「higher precedence」)。 ↩↩ -
出处:「Chapter 5. Expressions」第 888–890 段(
text/15-ch05-chapter-5-expressions.txt:888-890,搜「same type」)。 ↩ -
出处:「Chapter 5. Expressions」第 906 段(
text/15-ch05-chapter-5-expressions.txt:906,搜「increment and decrement」)。 ↩ -
出处:「Chapter 5. Expressions」第 894–906 段(
text/15-ch05-chapter-5-expressions.txt:894-906,搜「chaining」)。 ↩↩ -
出处:「Chapter 5. Expressions」第 910–929 段(
text/15-ch05-chapter-5-expressions.txt:910-929,搜「as keyword」)。 ↩ -
出处:「Chapter 5. Expressions」第 921–925 段(
text/15-ch05-chapter-5-expressions.txt:921-925,搜「surrogate」)。 ↩ -
出处:「Chapter 5. Expressions」第 931–943 段(
text/15-ch05-chapter-5-expressions.txt:931-943,搜「deref coercions」)。 ↩ -
出处:「Chapter 5. Expressions」第 947–955 段(
text/15-ch05-chapter-5-expressions.txt:947-955,搜「syntactic sanity」)。 ↩ -
出处:「Chapter 5. Expressions」第 961 段(
text/15-ch05-chapter-5-expressions.txt:961,搜「most delightful」)。 ↩ -
出处:「Chapter 5. Expressions」第 844–857 段(
text/15-ch05-chapter-5-expressions.txt:844-857,搜「underlying values」)。 ↩ -
出处:「Chapter 5. Expressions」第 877–886 段(
text/15-ch05-chapter-5-expressions.txt:877-886,搜「bitwise NOT」)。 ↩ -
出处:「Chapter 5. Expressions」第 873–875 段(
text/15-ch05-chapter-5-expressions.txt:873-875,搜「approximately」)。 ↩ -
出处:「Chapter 5. Expressions」第 892–902 段(
text/15-ch05-chapter-5-expressions.txt:892-902,搜「Compound assignment」)。 ↩ -
出处:「Chapter 5. Expressions」第 904–906 段(
text/15-ch05-chapter-5-expressions.txt:904-906,搜「chaining」)。 ↩ -
出处:「Chapter 5. Expressions」第 931–941 段(
text/15-ch05-chapter-5-expressions.txt:931-941,搜「Deref」)。 ↩ -
出处:「Chapter 5. Expressions」第 941 段(
text/15-ch05-chapter-5-expressions.txt:941,搜「underlying value」)。 ↩ -
出处:「Chapter 5. Expressions」第 945–961 段(
text/15-ch05-chapter-5-expressions.txt:945-961,搜「syntactic sanity」)。 ↩ -
出处:「Chapter 5. Expressions」第 751–756 段(
text/15-ch05-chapter-5-expressions.txt:751-756,搜「chained」)。 ↩ -
出处:「Chapter 5. Expressions」第 780–801 段(
text/15-ch05-chapter-5-expressions.txt:780-801,搜「lvalues」)。 ↩ -
出处:「Chapter 5. Expressions」第 809–825 段(
text/15-ch05-chapter-5-expressions.txt:809-825,搜「RangeFull」)。 ↩ -
出处:「Chapter 5. Expressions」第 751–756 段(
text/15-ch05-chapter-5-expressions.txt:751-756,搜「chained」)。 ↩