前言
这本书怎么组织
Section titled “这本书怎么组织”本书参考了各语言的官方文档(docs.python.org、developer.mozilla.org、typescriptlang.org、learn.microsoft.com/dotnet、go.dev)、Robert Nystrom 的《Crafting Interpreters》和 Michael L. Scott 的《Programming Language Pragmatics》;书中案例均为自行设计。全书按语言特性组织,每章讲一个特性,用 Python、JavaScript/TypeScript、C#、Go 四种语言把同一个任务各写一遍,再比较它们为什么做得不一样。第 1 章是全书的地图,介绍四种语言的出身、设计哲学和运行时,并用同一个小程序的五种写法让你先看到它们各自的样子。
之后的正文分七个部分。第一部分“语言的地基”讲程序怎么跑起来、类型系统、变量与可变性、值与引用和空值,这些是后面所有差异的根源。第二部分“抽象与组织”讲函数、类与接口、泛型、错误处理和模块,也就是代码怎么拆分、怎么复用。第三部分“数据”讲集合、迭代与惰性、字符串编码、枚举与模式匹配。第四部分“并发”从并发总览讲到多线程、多进程、异步、通道和取消,四种语言在这里分歧最大。第五部分“运行时与元编程”讲装饰器、特性、结构标签与反射,看程序怎么在运行时观察和改写自己。第六部分“看全局”讲语言之间在互相借鉴什么,以及从一种语言换到另一种时最容易踩的坑。第七部分“深入学习的资源”告诉你想在某个方向深挖时去哪里找资料,一章按语言整理官方文档、必读书、社区与工具,一章按类型系统、并发、内存、语言设计等主题整理书与论文。第一到第六部分开头各有一章导读,列出本部分各章,并告诉你“遇到什么问题先看哪章”。
书后有六个附录。附录 A 到 D 是四份速查表,分别对应 Python、JS/TS、C# 和 Go;附录 E 是跨语言对照表,一行一个常用概念,四列语言并排;附录 F 是术语表,收录正文里出现的术语及其英文名。正文和速查表分工明确:正文讲“为什么这样设计、和别的语言差在哪”,速查表只讲“怎么写”。两者互相指向:速查表里需要原理的条目会写“详见第 N 章”,正文里遇到看不懂的语法则可以翻到对应语言的速查表。
每一章的固定节奏
Section titled “每一章的固定节奏”特性章节开头是两行题记:一句话说这个特性解决什么问题,一句话概括四种语言对它的态度。之后的小节顺序全书统一,标题也不变:
- 一个场景:一个具体的小任务,全章四种语言都做这同一个任务。
- 概念本身:不依赖任何一种语言,讲这个机制是什么、有哪些流派、各自的取舍。
- Python 怎么做:Python 有没有这个特性(原生语法、靠标准库、只能模拟、还是没有),完整可运行的代码,底层怎么实现,以及两三个坑。
- JS/TS 怎么做:同上。大多数章节只给 TS;类型相关的章节把 JS 和 TS 分开讲。
- C# 怎么做:同上。
- Go 怎么做:同上。Go 没有某个特性时,这一节讲它用什么代替、设计者为什么不提供。
- 对比表:一张表,四种语言并排,前两行固定为“支持程度”和“实现机制”。
- 差异从哪来:解释为什么四种语言会做出不同的选择,以及这些选择带来的后果,例如能不能用多核、出错时程序怎么表现。这是全章比较分析的核心。
- 实践建议:在各语言里推荐怎么写、常见的错误用法。
- 练一练:一道题,用四种语言中的两种各写一遍,答案不在正文里。
- 小结:三到五条要点。
除了这十一个固定小节,差异从哪来之后还有一个可选的“旁注:别的语言”。它只在 Rust、Erlang/Elixir、Haskell/OCaml、Kotlin、C 或 Java 对这个特性有明显不同的做法时出现,只说那一点独特之处,不展开;没有值得说的,这一节就整节省略。
有三种读法。第一种从头读,适合想系统地比较几种语言的人,前面的章节为后面的章节准备了概念,例如第四部分的并发会用到闭包和错误处理。
第二种适合只会一种语言、正要学第二种的人:先读第 1 章,再把你会的那门语言和要学的那门语言的速查表各翻一遍,对两门语言的长相有个印象,然后按需要读特性章节。读特性章节时,你可以只细看这两门语言的“怎么做”,另外两门当作对照扫一眼,但“差异从哪来”值得完整读,它解释的正是你换语言时会撞上的那些不习惯。
第三种适合在多种语言之间来回切换的人:直接把附录 E 的对照表和各语言的速查表当工具用,想不起某个写法时去查,查到“详见第 N 章”再回正文。
各章基本独立,不必按顺序读。想看并发,可以直接跳到第四部分;遇到前面章节的概念,正文会写明出处。
运行代码前的准备
Section titled “运行代码前的准备”本书的代码覆盖四种语言,每个示例都是单文件,不依赖第三方库,运行方式如下:
| 语言 | 需要装什么 | 核对版本 | 运行 |
|---|---|---|---|
| Python | Python 3.12 以上 | python --version |
python x.py |
| JavaScript | Node 22 以上 | node --version |
node x.js |
| TypeScript | Node 22 以上,并全局装 tsx(npm install -g tsx) |
tsx --version |
tsx x.ts |
| C# | .NET 10 SDK 以上 | dotnet --version |
dotnet run x.cs |
| Go | Go 1.23 以上 | go version |
go run x.go |
你不需要装齐四种。只装你正在用和正在学的那一两种,其余语言的代码当作对照阅读即可。预期输出写在每个文件末尾的注释里,跑完对照。如果输出和注释不一致,先检查版本,再检查是否完整复制了整个文件。
本书全部代码的下载方式见本书介绍页。
- 术语第一次出现时给出英文原名,之后用中文名。
- 同一个案例总是按 Python、JS/TS、C#、Go 的顺序出现。四个版本做同一件事,命名和输出保持一致,所以你只熟悉其中一种语言也能对照着读懂其他几种。
- 代码文件末尾
# 输出:(Python)或// 输出:(其余语言)下面的注释,是整个文件运行后应该打印的结果。 - 对比表格子里的代码片段只是示意,用来点出写法上的差别,不是完整程序,不能直接运行。
- JS 和 TS 在大多数章节合为一列,因为 TS 的运行时行为就是 JS 的行为;只在类型系统、泛型、模块、枚举与联合这几章分开讲。