从 Kotlin 过来:一张对照表
如果你写 Kotlin(尤其做 Android),你比自己以为的更接近 Rust —— Kotlin 是主流语言里离 Rust 最近的一门。这一章把你已有的每个概念,对到 Rust 上,并标出「哪些直接迁移、哪些有出入、哪个是真·全新」。剧透:真正全新的只有一样,就是这本书花了整整一卷讲的那个 —— 所有权。
好消息:一大半能直接搬过来
Kotlin 这些年吸收了大量函数式和现代类型系统的设计,很多正是 Rust(以及它们共同的祖先 ML / Haskell)那一脉的。所以你有一整套直觉是通用的:
| Kotlin | Rust | 差别 |
|---|---|---|
data class User(...) | struct User { ... } + #[derive(...)] | Rust 的 derive 要你显式列出要哪些(Clone/Debug/PartialEq…),Kotlin data class 自动全给 |
sealed class / sealed interface | enum | 几乎一一对应;Rust 枚举是值类型不装箱,更轻 |
when (x) { ... } | match x { ... } | 都穷尽、都是表达式;Rust 的模式解构更强 |
String?(可空类型) | Option<String> | 同一个思想;Kotlin 用 ? 语法糖,Rust 用普通枚举 + 组合子 |
?. / ?: / !! | .map()/.and_then() / unwrap_or / .unwrap() | !! 就是 .unwrap(),都是「担保非空、错了就崩」 |
interface | trait | trait 能为已有类型实现、能静态分发(零成本),更强(第 13 章) |
扩展函数 fun T.foo() | impl 块 / 为已有类型 impl Trait | Rust 的更「正规」,还能当多态约束 |
Result / runCatching | Result<T, E> + ? | Rust 的 ? 比 Kotlin 顺;且 Rust 无异常,纯值 |
协程 suspend fun | async fn + .await | 都是状态机(第 20 章);Kotlin 挂起点隐式、自带调度器,Rust 用显式 .await + 选运行时 |
listOf / map / filter / 序列 | vec! / Iterator 的 .map().filter() | 几乎一样的链式风格;Rust 迭代器惰性、零成本 |
表达式导向(if/when 是表达式) | 同样表达式导向 | Rust 里连 { } 块、loop 都是表达式,更彻底 |
默认不可变(val 优先) | 默认不可变(let,要 mut 才可变) | 方向一致;Rust 更严格(连可变借用都要 mut) |
看这张表,你会有种踏实感:Rust 对你不是一门外星语言。枚举 + match、null 安全、密封类、协程、扩展、不可变优先 —— 这些让 Kotlin 感觉「现代」的东西,你在 Rust 里全能找到近亲。你写 Kotlin 养成的很多好直觉,过来就能用。
真·全新的,只有一样
上面那张表里,没有一行对得上「所有权 / 借用 / 生命周期」—— 因为 JVM 有 GC,Kotlin 从不需要你想「这个值归谁、谁能改它、什么时候释放」。这正是这本书卷 II 花了整整六章、还配了一台借用检查器的原因:它是你唯一真正要从零建立的心智模型。
换个角度看,这也是好消息:你被 Rust 劝退,几乎可以肯定就是卡在这一样上 —— 因为其余的你本来就会。把所有权吃透(你读到这里,应该已经吃透了),Rust 剩下的部分对一个 Kotlin 老手来说,是顺水推舟。
几个要主动放下的旧习惯
迁移不只是「学新的」,也包括「放下旧的」。有几个 Kotlin/JVM 的习惯,到 Rust 会绊你,得主动改:
- 放下「继承」。Rust 没有类继承。你在 Kotlin 里用
open class+ 继承做的事,在 Rust 里用「组合 + trait」来做 —— 把共享行为抽成 trait,把共享数据用字段组合进来。一开始别扭,但你会发现绝大多数继承本来就该是组合。(Kotlin 官方也一直在推「组合优于继承」,Rust 只是把它变成了唯一选项。) - 放下「到处 new 一个对象、随便传引用」。这在 JVM 上是默认、免费的(GC 兜底);在 Rust 里,每次这么做你都要想清楚所有权。默认试着用栈上的值、用借用,只在真需要共享时才
Rc/Arc(第 15、19 章)。 - 放下「用异常做控制流」。Rust 没有异常。可预期的失败用
Result(第 12 章),别想着 try/catch。 - 放下
lateinit/ 到处可空。Rust 里一个值要么初始化了、要么根本还没绑定,没有lateinit那种「声明了但还没值」的中间态。这逼你把初始化顺序想清楚 —— 通常是好事。 - 接受更长的编译时间。单态化(第 14 章)让 Rust 编译比 Kotlin 慢。习惯用
cargo check做快速反馈(第 3 章)。
一个 Android 老兵的实感
你可能会问:学了 Rust,对我写 Android 有什么用?两条很实在:
一,你会成为更好的 Kotlin 程序员。建立起所有权直觉之后,你回头写 Kotlin,会本能地警觉「这个 mutable list 被两个地方持有了」「这个对象的生命周期是不是拖太长导致内存泄漏」—— 这些正是 Android 上 Context 泄漏、ViewModel 状态混乱、协程作用域用错的根源。Rust 强制你练的那套内存纪律,会渗进你所有的代码。
二,Rust 在移动端是真有用武之地的。性能敏感的核心逻辑(音视频、加密、图像处理、跨平台业务内核)用 Rust 写、通过 JNI/NDK 给 Kotlin 调,是越来越常见的架构 —— 一份 Rust 核心,Android 和 iOS 共用,还没有 GC 停顿。你手上的 Kotlin 技能 + Rust,是一个很有竞争力的组合。
回流
这本书每章末尾的「回流」,讲的都是「这一课在你熟悉的语言里长什么样」。而这一整章,是把二十多次回流汇成一张总表。如果你从头读到这里,回头再扫一眼各章的回流小节,你会发现一件事:Rust 没有凭空发明太多东西 —— 它是把散落在各语言里的好设计(Kotlin 的 null 安全、Haskell 的 typeclass、C++ 的 RAII 和移动、Go 的错误即值、ML 的和类型)收拢起来,再用「所有权」这条主线把它们焊成一个自洽的、安全的整体。你学 Rust,某种意义上是在系统地复习整个编程语言设计史上最好的那些主意。
这一章的一句话
Kotlin 是离 Rust 最近的主流语言:枚举、match、null 安全、trait、协程,你的直觉大半能直接搬。真正全新的只有所有权 —— 而那恰恰是你被劝退的那一样。放下继承、放下随手 new、放下异常,你就上路了。
最后一章,我们收束全书,给你一份上路地图和几句送行的话 —— 关于「不再被劝退之后」,该往哪走。