<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>编程语言横向对照 on 编程那些事儿</title><link>https://before80.github.io/prgms/diff/</link><description>Recent content in 编程语言横向对照 on 编程那些事儿</description><generator>Hugo</generator><language>zh-cn</language><lastBuildDate>Sat, 19 Sep 2026 22:16:04 +0800</lastBuildDate><atom:link href="https://before80.github.io/prgms/diff/index.xml" rel="self" type="application/rss+xml"/><item><title>数据类型对照</title><link>https://before80.github.io/prgms/diff/types/</link><pubDate>Fri, 18 Sep 2026 22:24:56 +0800</pubDate><guid>https://before80.github.io/prgms/diff/types/</guid><description>&lt;h1 id="数据类型对照18-种语言"&gt;数据类型对照：18 种语言&lt;/h1&gt;
&lt;p&gt;同一件东西——&amp;ldquo;一个整数&amp;rdquo;——在 18 种语言里有 18 种说法：有的语言默认只有 32 位，有的干脆没有上限；有的溢出就崩溃，有的溢出悄悄给你一个负数，有的语言&lt;strong&gt;根本没有整型&lt;/strong&gt;。本页按数据类型分类，每一类用标签页切换语言，每个标签里给出：&lt;strong&gt;类型清单 → 定义与字面量 → 最值 → 计算与溢出 → 比较 → 常见陷阱&lt;/strong&gt;。没有这个类型的语言，会直接说明&amp;quot;没有&amp;quot;以及通常的替代做法。&lt;/p&gt;</description></item><item><title>关键字与保留字</title><link>https://before80.github.io/prgms/diff/keywords/</link><pubDate>Sat, 19 Sep 2026 10:00:00 +0800</pubDate><guid>https://before80.github.io/prgms/diff/keywords/</guid><description>&lt;h1 id="关键字与保留字18-种语言对照"&gt;关键字与保留字：18 种语言对照&lt;/h1&gt;
&lt;h2 id="关键字与保留字"&gt;关键字与保留字&lt;/h2&gt;
&lt;p&gt;关键字是语言&amp;quot;自己留着用&amp;quot;的词汇：它们不能（或不能随便）当作变量名、函数名、类型名。但&amp;quot;保留&amp;quot;这件事在不同语言里分好几层——&lt;strong&gt;硬关键字&lt;/strong&gt;永远不能用，&lt;strong&gt;软关键字/上下文关键字&lt;/strong&gt;只在特定语法位置才是关键字，&lt;strong&gt;保留但未使用&lt;/strong&gt;是给未来留的位置，&lt;strong&gt;特殊值&lt;/strong&gt;（&lt;code&gt;true&lt;/code&gt;, &lt;code&gt;nil&lt;/code&gt;, &lt;code&gt;None&lt;/code&gt;, &lt;code&gt;this&lt;/code&gt;）则是语言内建的常量与单例。本页按这五层组织，每个主题一套 18 语言标签页；每门语言都给出完整清单、可以实际运行的示例，以及&amp;quot;想用这个名字怎么办&amp;quot;的规避写法。&lt;/p&gt;</description></item><item><title>编译与执行</title><link>https://before80.github.io/prgms/diff/compile/</link><pubDate>Sat, 19 Sep 2026 09:00:00 +0800</pubDate><guid>https://before80.github.io/prgms/diff/compile/</guid><description>&lt;h1 id="编译与执行18-种语言对照"&gt;编译与执行：18 种语言对照&lt;/h1&gt;
&lt;p&gt;&amp;ldquo;怎么把代码跑起来&amp;quot;是每门语言的第一课，但 18 种语言给出的答案完全不同：Rust 先编译成机器码再运行，Python 交给解释器直接执行，Java 编译成字节码交给 JVM 的 JIT，TypeScript 先把类型擦掉再转译成 JavaScript，Ruby 边解释边可选 JIT。本页按五个主题组织：&lt;strong&gt;执行模型与入口 → 单文件编译运行命令 → 构建系统与依赖管理 → 编译产物与中间表示 → 优化、发布与调试&lt;/strong&gt;，每个主题一套 18 语言标签页，命令都给可直接粘贴的完整写法。&lt;/p&gt;</description></item><item><title>错误处理机制</title><link>https://before80.github.io/prgms/diff/error/</link><pubDate>Sat, 19 Sep 2026 09:05:00 +0800</pubDate><guid>https://before80.github.io/prgms/diff/error/</guid><description>&lt;h1 id="错误处理机制18-种语言对照"&gt;错误处理机制：18 种语言对照&lt;/h1&gt;
&lt;p&gt;错误处理是语言设计分歧最大的地方之一：Rust 把错误当&lt;strong&gt;值&lt;/strong&gt;返回，Go 用 &lt;code&gt;error&lt;/code&gt; 接口加 &lt;code&gt;if err != nil&lt;/code&gt;，Java 区分 checked/unchecked 异常，Python/JavaScript 抛任意对象，Zig 用错误集与 &lt;code&gt;try&lt;/code&gt;，Lua 用 &lt;code&gt;pcall&lt;/code&gt; 返回的字符串。本页按五个主题组织：&lt;strong&gt;错误的表示方式 → 抛出与传播 → 捕获与处理 → 自定义错误与上下文 → 资源清理与未捕获错误&lt;/strong&gt;，每个主题一套 18 语言标签页。&lt;/p&gt;</description></item><item><title>包管理与模块</title><link>https://before80.github.io/prgms/diff/package/</link><pubDate>Sat, 19 Sep 2026 09:10:00 +0800</pubDate><guid>https://before80.github.io/prgms/diff/package/</guid><description>&lt;h1 id="包管理与模块18-种语言对照"&gt;包管理与模块：18 种语言对照&lt;/h1&gt;
&lt;p&gt;&amp;ldquo;包管理&amp;quot;要回答四个问题：&lt;strong&gt;代码怎么分组&lt;/strong&gt;（模块/命名空间）、&lt;strong&gt;依赖怎么声明与锁定&lt;/strong&gt;（清单 + 锁文件）、&lt;strong&gt;包怎么发布与获取&lt;/strong&gt;（注册中心）、&lt;strong&gt;版本怎么解析&lt;/strong&gt;（语义化版本与冲突处理）。本页按这四个主题组织，每个主题一套 18 语言标签页；命令与文件名都给可直接照抄的写法。&lt;/p&gt;</description></item><item><title>基本运算</title><link>https://before80.github.io/prgms/diff/operations/</link><pubDate>Sat, 19 Sep 2026 09:40:00 +0800</pubDate><guid>https://before80.github.io/prgms/diff/operations/</guid><description>&lt;h1 id="基本运算18-种语言对照"&gt;基本运算：18 种语言对照&lt;/h1&gt;
&lt;p&gt;运算符看起来是全世界通用的符号，但每门语言都给它们塞进了不同的语义：&lt;code&gt;/&lt;/code&gt; 在 Python 里永远给浮点、在 Ruby 里是地板除、在 C 里是截断除；&lt;code&gt;%&lt;/code&gt; 的符号在 C 系跟被除数、在 Python/R 里跟除数；&lt;code&gt;==&lt;/code&gt; 在 JavaScript 里会做类型转换，在 Kotlin 里等价于 &lt;code&gt;equals&lt;/code&gt;。本页按三个主题组织：&lt;strong&gt;算术运算 → 位运算与移位 → 比较与逻辑运算&lt;/strong&gt;，每个主题一套 18 语言标签页；类型转换与运算符优先级单独放在 &lt;a href="https://before80.github.io/prgms/diff/typeTrans/"&gt;typeTrans&lt;/a&gt; 一页。&lt;/p&gt;</description></item><item><title>类型转换</title><link>https://before80.github.io/prgms/diff/typeTrans/</link><pubDate>Sat, 19 Sep 2026 10:00:00 +0800</pubDate><guid>https://before80.github.io/prgms/diff/typeTrans/</guid><description>&lt;h1 id="类型转换18-种语言对照"&gt;类型转换：18 种语言对照&lt;/h1&gt;
&lt;p&gt;类型转换的分歧可以归结为四个问题：&lt;strong&gt;会不会偷偷替你转&lt;/strong&gt;（隐式提升）、&lt;strong&gt;怎么显式转&lt;/strong&gt;（&lt;code&gt;as&lt;/code&gt;/&lt;code&gt;Int()&lt;/code&gt;/&lt;code&gt;@intCast&lt;/code&gt;/&lt;code&gt;T(x)&lt;/code&gt;）、&lt;strong&gt;转换失败会怎样&lt;/strong&gt;（截断、饱和、抛异常、变 &lt;code&gt;NA&lt;/code&gt;）、&lt;strong&gt;什么时候转&lt;/strong&gt;（运算符优先级与求值顺序）。本页按这四个主题组织，每个主题一套 18 语言标签页。&lt;/p&gt;</description></item><item><title>控制流</title><link>https://before80.github.io/prgms/diff/ctrls/</link><pubDate>Sat, 19 Sep 2026 12:00:00 +0800</pubDate><guid>https://before80.github.io/prgms/diff/ctrls/</guid><description>&lt;h1 id="控制流18-种语言对照"&gt;控制流：18 种语言对照&lt;/h1&gt;
&lt;p&gt;条件、循环、跳转、迭代这四件事看着是编程语言的公分母，但每门语言对「控制流能不能有值」的回答截然不同：Rust、Swift、Kotlin 把 &lt;code&gt;if&lt;/code&gt;、&lt;code&gt;switch&lt;/code&gt;/&lt;code&gt;when&lt;/code&gt;、&lt;code&gt;loop&lt;/code&gt; 一律做成表达式，C、Go、Java 的传统形式则只是语句；Python、C#、Dart、Ruby 在各自的新版本里补上了结构化模式匹配，而 C、C++、Go、Lua、R 至今只有 &lt;code&gt;switch&lt;/code&gt;/&lt;code&gt;case&lt;/code&gt;/&lt;code&gt;if&lt;/code&gt; 链。本页按 &lt;strong&gt;条件分支与模式匹配 → 循环 → 跳转与提前退出 → 迭代协议与生成器&lt;/strong&gt; 四个主题组织，每个主题一套 18 语言标签页。前两个主题回答「怎么选、怎么重复」，后两个主题回答「怎么提前离开」与「怎么把遍历抽象成协议」。真正拉开差距的往往不是关键字拼写，而是穷尽性检查、作用域规则、标签跳转和迭代器协议这四件事。&lt;/p&gt;</description></item><item><title>函数</title><link>https://before80.github.io/prgms/diff/fns/</link><pubDate>Sat, 19 Sep 2026 12:00:00 +0800</pubDate><guid>https://before80.github.io/prgms/diff/fns/</guid><description>&lt;h1 id="函数18-种语言对照"&gt;函数：18 种语言对照&lt;/h1&gt;
&lt;p&gt;函数的语法分歧远小于它的语义分歧：同样一句 &lt;code&gt;f(x)&lt;/code&gt;，在 C 里传的是值的一份拷贝，在 Python 里传的是对象引用的一份拷贝，在 Rust 里可能已经把 &lt;code&gt;x&lt;/code&gt; 的 ownership 移走，在 Java 里传的则是对象引用的值拷贝。本页按六个主题推进：&lt;strong&gt;函数定义与签名&lt;/strong&gt;（关键字、返回类型位置、默认参数、命名实参、变参、&lt;code&gt;main&lt;/code&gt;）→ &lt;strong&gt;参数传递与返回值&lt;/strong&gt;（值/引用语义、ownership、多返回值）→ &lt;strong&gt;一等函数&lt;/strong&gt;（函数类型、函数指针、函数引用、高阶函数、柯里化）→ &lt;strong&gt;闭包与匿名函数&lt;/strong&gt;（lambda 字面量、捕获结论、逃逸与生命周期）→ &lt;strong&gt;重载&lt;/strong&gt;（编译期按类型选实现、运行期多重分派、以及干脆没有重载时的替代）→ &lt;strong&gt;泛型与装饰&lt;/strong&gt;（泛型函数的约束写法、装饰器/注解/宏/源生成器）。这里只讲函数本身：闭包捕获语义与循环变量陷阱的细节归 closure.md，泛型的类型层面细节归 generic.md。&lt;/p&gt;</description></item><item><title>闭包</title><link>https://before80.github.io/prgms/diff/closure/</link><pubDate>Sat, 19 Sep 2026 12:00:00 +0800</pubDate><guid>https://before80.github.io/prgms/diff/closure/</guid><description>&lt;h1 id="闭包18-种语言对照"&gt;闭包：18 种语言对照&lt;/h1&gt;
&lt;p&gt;闭包把函数和它引用的环境绑在一起，但&amp;quot;环境&amp;quot;在各语言里的含义完全不同。捕获语义要回答三件事：&lt;strong&gt;按值捕获&lt;/strong&gt;（创建时拷一份快照）、&lt;strong&gt;按引用捕获&lt;/strong&gt;（内外共享同一份存储）、&lt;strong&gt;按移动捕获&lt;/strong&gt;（把所有权搬进闭包），以及由谁声明这件事。本页按四个主题组织：&lt;strong&gt;捕获语义 → 生命周期与逃逸 → 闭包与循环变量 → 实际用途&lt;/strong&gt;，每个主题一套 18 语言标签页。最根本的分歧在两条轴上：一条是 Rust、C++、Swift 走&amp;quot;编译期规则 + 显式标注&amp;quot;，另一条是 Python、Ruby、JavaScript、PHP 走&amp;quot;运行时对象 + 隐式捕获&amp;quot;；Go、Java、C#、Kotlin、Dart 站在中间，用运行时对象实现、再用语言规则限定捕获的形态。C 与 Zig 干脆没有闭包，一律用&amp;quot;函数指针 + 显式上下文&amp;quot;手工模拟。&lt;/p&gt;</description></item><item><title>枚举</title><link>https://before80.github.io/prgms/diff/enums/</link><pubDate>Sat, 19 Sep 2026 12:00:00 +0800</pubDate><guid>https://before80.github.io/prgms/diff/enums/</guid><description>&lt;h1 id="枚举18-种语言对照"&gt;枚举：18 种语言对照&lt;/h1&gt;
&lt;p&gt;枚举在多数人印象里就是「给整数起名字」，可一旦跨语言看，它其实分裂成三种完全不同的东西：C/C++/Go/Java 路线把它当成&lt;strong&gt;整数的别名或整数的包装&lt;/strong&gt;，Rust/Swift/Kotlin/Zig 路线把它当成&lt;strong&gt;只能取有限几个构造子的类型&lt;/strong&gt;（Rust 的 &lt;code&gt;enum&lt;/code&gt; 是代数数据类型，Zig 的 &lt;code&gt;enum&lt;/code&gt; 可以带 payload），Lua/JavaScript/R/Ruby 路线则干脆&lt;strong&gt;没有枚举&lt;/strong&gt;，用 table、&lt;code&gt;Object.freeze&lt;/code&gt;、&lt;code&gt;factor&lt;/code&gt;、&lt;code&gt;Symbol&lt;/code&gt; 这些更基础的东西凑出等价效果。前一种路线的枚举值是数字，可以隐式转成整数、可以拿到不存在的值；后一种路线的枚举值只能来自声明过的构造子，编译器能替你检查穷尽性。本页按三个主题层层推进：&lt;strong&gt;定义与底层表示&lt;/strong&gt;先确认每种语言的枚举到底是什么、占几个字节、序列化成什么；&lt;strong&gt;取值、转换与遍历&lt;/strong&gt;看序号与底层值怎么互换、遍历顺序可不可靠、未知值怎么处理；&lt;strong&gt;带数据的枚举与模式匹配&lt;/strong&gt;看哪些语言真的能做和类型（sum type），穷尽性检查是编译期保证还是运行时兜底。每一节都是一套 18 语言标签页，顺序固定，没有该机制的语言会明确写出「没有」并给出常规替代做法。&lt;/p&gt;</description></item><item><title>方法</title><link>https://before80.github.io/prgms/diff/methods/</link><pubDate>Sat, 19 Sep 2026 12:00:00 +0800</pubDate><guid>https://before80.github.io/prgms/diff/methods/</guid><description>&lt;h1 id="方法18-种语言对照"&gt;方法：18 种语言对照&lt;/h1&gt;
&lt;p&gt;函数是大家都有的东西，方法却不是：它是一段代码加上一个&amp;quot;接收者&amp;quot;。本页按四个主题组织这条线索。&lt;strong&gt;定义与接收者&lt;/strong&gt;回答&amp;quot;接收者写在哪里&amp;quot;——Rust 放进 &lt;code&gt;impl&lt;/code&gt; 块、Go 写在函数名前的括号里、Python 把它变成第一个显式参数、C 干脆没有。&lt;strong&gt;方法与函数的关系&lt;/strong&gt;回答&amp;quot;方法能不能变回普通函数&amp;quot;——Go 的方法表达式、Rust 的 UFCS、C++ 的成员函数指针，以及各语言的扩展方法。&lt;strong&gt;方法解析与派发&lt;/strong&gt;回答&amp;quot;调用哪一份实现、什么时候决定&amp;quot;——是编译期静态绑定还是查 vtable，是单分派还是多分派。&lt;strong&gt;特殊方法&lt;/strong&gt;回答&amp;quot;构造、析构、运算符怎么用方法表达&amp;quot;。最根本的分歧只有两条：接收者是值还是引用、名字到实现的绑定发生在编译期还是运行时；其余所有差异几乎都能从这两条推出来。&lt;/p&gt;</description></item><item><title>继承</title><link>https://before80.github.io/prgms/diff/inherit/</link><pubDate>Sat, 19 Sep 2026 12:00:00 +0800</pubDate><guid>https://before80.github.io/prgms/diff/inherit/</guid><description>&lt;h1 id="继承18-种语言对照"&gt;继承：18 种语言对照&lt;/h1&gt;
&lt;p&gt;继承在大多数教材里被当成面向对象的起点，但 18 门语言给出的答案是分裂的：Java、C#、Kotlin、Swift、Dart、PHP、Ruby 只允许单继承并用接口或 mixin 补足横向复用，C++ 允许真正的多继承（并因此背上菱形与虚继承），Python 允许类多继承但要靠 MRO 线性化，而 Rust、Go、Julia、Zig、C、Lua、R 干脆没有继承关键字，各自用 trait、嵌入、多分派、组合、元表和泛型函数解决问题。本页因此按三条线索组织：先看&lt;strong&gt;继承与子类型&lt;/strong&gt;（谁有继承、谁只有子类型关系），再看&lt;strong&gt;覆盖与多态&lt;/strong&gt;（&lt;code&gt;virtual&lt;/code&gt;/&lt;code&gt;override&lt;/code&gt;/&lt;code&gt;final&lt;/code&gt;/&lt;code&gt;sealed&lt;/code&gt; 的完整矩阵与派发机制），然后看&lt;strong&gt;没有继承的语言怎么复用&lt;/strong&gt;（这才是多数现代语言的实际做法），最后集中记录&lt;strong&gt;继承的陷阱&lt;/strong&gt;——脆弱基类、菱形、对象切片、构造期调用被覆盖方法、&lt;code&gt;equals&lt;/code&gt;/&lt;code&gt;hashCode&lt;/code&gt; 契约破坏等。理解这四组差异之后，语言选型时&amp;quot;要不要给类开 &lt;code&gt;open&lt;/code&gt;&amp;ldquo;这类问题就不再是口味问题，而是可推演的工程判断。&lt;/p&gt;</description></item><item><title>泛型</title><link>https://before80.github.io/prgms/diff/generic/</link><pubDate>Sat, 19 Sep 2026 12:00:00 +0800</pubDate><guid>https://before80.github.io/prgms/diff/generic/</guid><description>&lt;h1 id="泛型18-种语言对照"&gt;泛型：18 种语言对照&lt;/h1&gt;
&lt;p&gt;泛型的写法只是表层，真正的分歧藏在这四个子主题里：&lt;strong&gt;怎么写约束&lt;/strong&gt;（trait bound、concept、interface 类型集、协议约束、docblock 注解）、&lt;strong&gt;子类型关系怎么传导&lt;/strong&gt;（协变、逆变、不变）、&lt;strong&gt;代码最终怎么生成&lt;/strong&gt;（单态化、类型擦除、具体化）、&lt;strong&gt;运行时还剩多少类型信息&lt;/strong&gt;（&lt;code&gt;typeof(T)&lt;/code&gt;、&lt;code&gt;TypeId&lt;/code&gt;、反射、完全擦掉）。这四件事互相牵制：选了单态化就换来性能但失去异构容器，选了擦除就换来代码体积但拿不到 &lt;code&gt;T&lt;/code&gt;，选了具体化就保住了反射却背上 CLR/VM 的运行时元数据。本页先把 18 种语言放到同一张速览表里对齐，再逐个主题展开。按「语言本身是否提供类型参数」统计（口径：本文件 18 种语言全算），完全没有类型参数的 6 种是 C、Lua、R、Ruby、PHP、JavaScript，它们分别用 &lt;code&gt;void *&lt;/code&gt; 加 &lt;code&gt;_Generic&lt;/code&gt;、元表、S3/S4 分派、duck typing、docblock 加 PHPStan/Psalm、JSDoc &lt;code&gt;@template&lt;/code&gt; 顶替；其余 12 种（Rust、Swift、Go、Python、Kotlin、Java、C++、Julia、C#、Dart、Zig、TypeScript）都有类型参数，但各有短板——Go 与 Zig 没有型变概念，Python 的类型参数只活在注解里，Java 的类型实参擦除后不剩，C# 的声明处型变只覆盖接口与委托。&lt;/p&gt;</description></item><item><title>编译选项</title><link>https://before80.github.io/prgms/diff/compileOptions/</link><pubDate>Sat, 19 Sep 2026 12:00:00 +0800</pubDate><guid>https://before80.github.io/prgms/diff/compileOptions/</guid><description>&lt;h1 id="编译选项18-种语言对照"&gt;编译选项：18 种语言对照&lt;/h1&gt;
&lt;p&gt;编译选项是横向对照里最难对齐的一块，因为「优化」这件事在 18 门语言里发生在完全不同的时刻：C、C++、Rust、Swift、Zig 在构建期由编译器静态完成，Java、C#、JavaScript 在运行期由 JIT 在方法变热之后才做，Python、Ruby、PHP、Lua、R 则只有解释器与字节码缓存级别的开关，根本没有「优化等级」这个旋钮。选项的载体也各不相同：C 系是纯命令行 flag，Rust 写进 &lt;code&gt;Cargo.toml&lt;/code&gt; 的 profile，Java 靠 &lt;code&gt;-XX:&lt;/code&gt; 之类的 JVM 参数，TypeScript 与 C# 把大部分配置放进 &lt;code&gt;tsconfig.json&lt;/code&gt; 与 &lt;code&gt;.csproj&lt;/code&gt;，Go 甚至只留了 &lt;code&gt;-gcflags&lt;/code&gt; 一个后门。本页把这块拆成四组：&lt;strong&gt;优化等级 → 体积与链接 → 运行时与目标控制 → 调试与分析开关&lt;/strong&gt;，每组一套 18 语言标签页，代码块里给的是可直接粘贴的 shell 命令与实测输出。理解这条分组逻辑的关键是分清「编译器选项」与「运行时/解释器选项」：&lt;code&gt;-O2&lt;/code&gt;、&lt;code&gt;-C opt-level&lt;/code&gt;、&lt;code&gt;-gcflags&lt;/code&gt; 属于前者，&lt;code&gt;--yjit&lt;/code&gt;、&lt;code&gt;PYTHON_JIT&lt;/code&gt;、&lt;code&gt;-XX:TieredStopAtLevel&lt;/code&gt;、&lt;code&gt;node --max-old-space-size&lt;/code&gt; 属于后者，把两者混为一谈是这类配置最常见的事故来源。&lt;/p&gt;</description></item><item><title>访问控制</title><link>https://before80.github.io/prgms/diff/accessCtrl/</link><pubDate>Sat, 19 Sep 2026 12:00:00 +0800</pubDate><guid>https://before80.github.io/prgms/diff/accessCtrl/</guid><description>&lt;h1 id="访问控制18-种语言对照"&gt;访问控制：18 种语言对照&lt;/h1&gt;
&lt;p&gt;访问控制这件事，各语言的分歧点在四个层面依次展开：&lt;strong&gt;第一个层面是类或类型的成员修饰符&lt;/strong&gt;（&lt;code&gt;public&lt;/code&gt;/&lt;code&gt;private&lt;/code&gt;/&lt;code&gt;protected&lt;/code&gt; 这一套到底有几个、默认是哪一级）；&lt;strong&gt;第二个层面是模块与文件的边界&lt;/strong&gt;（封装单位是类、是文件、是包、还是 crate，边界不同则同一个关键字含义完全不同）；&lt;strong&gt;第三个层面是没有强制机制时怎么表达私有&lt;/strong&gt;（下划线约定、名称改写、闭包）；&lt;strong&gt;第四个层面是这些边界能不能被反射和内存操作绕过去&lt;/strong&gt;。这四个层面构成本页的四个子主题，每个子主题一套 18 语言标签页。最根本的分歧可以归纳成一句话：有的语言把可见性当成&lt;strong&gt;编译期契约&lt;/strong&gt;，编译通过、运行时想怎么看就怎么看（TypeScript、C++、Java 的 &lt;code&gt;private&lt;/code&gt; 都在此列）；有的语言把它当成&lt;strong&gt;运行时的真边界&lt;/strong&gt;，语言层面根本不提供通向内部的路径（JavaScript 的 &lt;code&gt;#&lt;/code&gt;、Rust 的 &lt;code&gt;mod&lt;/code&gt; 私有、Dart 的库级下划线、Lua 的闭包 upvalue）；还有一批语言&lt;strong&gt;压根不做强制&lt;/strong&gt;，只留下划线这类命名约定（Python、R、Julia、Lua 的表字段）。本页反复回到的核心区分就是「真私有」与「编译期私有」，请读者在每个子主题里都拿这把尺子去量一遍。&lt;/p&gt;</description></item><item><title>宏</title><link>https://before80.github.io/prgms/diff/macro/</link><pubDate>Sat, 19 Sep 2026 12:00:00 +0800</pubDate><guid>https://before80.github.io/prgms/diff/macro/</guid><description>&lt;h1 id="宏18-种语言对照"&gt;宏：18 种语言对照&lt;/h1&gt;
&lt;p&gt;宏是唯一一类&amp;quot;写起来像函数、实际却不是函数&amp;quot;的机制。本页按四个主题递进：&lt;strong&gt;预处理宏&lt;/strong&gt;看 C/C++ 的文本替换到底提供了什么、&lt;strong&gt;声明式与语法宏&lt;/strong&gt;看 Rust 与 Julia 如何把宏做成语法树层面的模式匹配、&lt;strong&gt;过程宏与编译期代码生成&lt;/strong&gt;看编译器怎样被当成一个库来调用、&lt;strong&gt;没有宏的语言用什么替代&lt;/strong&gt;看装饰器、元编程、代码生成与泛型各自能顶替到什么程度。最根本的分歧在于替换发生在哪一层：C 的预处理器在词法层做字符串替换，Rust 与 Julia 在语法树层做结构匹配，C# 的源生成器与 Java 的注解处理器干脆把工作交给一个在编译过程中运行的普通程序。第二个分岔是卫生性（hygiene），Rust 与 Julia 的宏默认让宏内新引入的名字不与调用点冲突，C 的宏什么也不保证。第三个分岔是时机，C# 与 Java 的生成器只能&lt;strong&gt;新增&lt;/strong&gt;源码，不能修改已有的声明，这决定了它们能表达什么。&lt;/p&gt;</description></item><item><title>内存安全</title><link>https://before80.github.io/prgms/diff/memorySafe/</link><pubDate>Sat, 19 Sep 2026 12:00:00 +0800</pubDate><guid>https://before80.github.io/prgms/diff/memorySafe/</guid><description>&lt;h1 id="内存安全18-种语言对照"&gt;内存安全：18 种语言对照&lt;/h1&gt;
&lt;p&gt;内存安全不是&amp;quot;有没有垃圾回收&amp;quot;这么简单的问题，它由三层东西叠起来：&lt;strong&gt;内存怎么分配和释放&lt;/strong&gt;（手动、引用计数、追踪式 GC、编译期所有权）、&lt;strong&gt;哪些操作一旦写错就不再是&amp;quot;错误&amp;quot;而是&amp;quot;未定义行为&amp;quot;&lt;/strong&gt;（越界、悬垂、数据竞争）、以及&lt;strong&gt;语言把保证做到哪一步、又留了哪些官方的逃逸通道&lt;/strong&gt;（&lt;code&gt;unsafe&lt;/code&gt;、FFI、反射、C 扩展）。本页按这四层组织：先看&lt;strong&gt;内存模型与所有权&lt;/strong&gt;，再看&lt;strong&gt;安全边界&lt;/strong&gt;里各语言对 UB 的定义差异，然后是&lt;strong&gt;安全保证与逃逸通道&lt;/strong&gt;，最后是&lt;strong&gt;常见问题与检测工具&lt;/strong&gt;。各语言最根本的分歧在于：C 与 C++ 把内存完全交给程序员，Rust 用编译期所有权把大部分检查提前到编译期，Zig 把安全检查做成可切换的构建模式，而 Java、C#、Go、Swift、Dart、JavaScript 把保证放在运行时，Python、Ruby、PHP、Lua、R、Julia 则依靠&amp;quot;错误的操作抛异常&amp;quot;这一层薄薄的运行时约定。&lt;/p&gt;</description></item><item><title>正则表达式</title><link>https://before80.github.io/prgms/diff/regex/</link><pubDate>Sat, 19 Sep 2026 21:00:00 +0800</pubDate><guid>https://before80.github.io/prgms/diff/regex/</guid><description>&lt;h1 id="正则表达式18-种语言对照"&gt;正则表达式：18 种语言对照&lt;/h1&gt;
&lt;p&gt;&amp;ldquo;正则&amp;quot;这个词掩盖了三件完全不同的事：&lt;strong&gt;有的语言根本没有正则&lt;/strong&gt;（C 只借用了 POSIX 的 &lt;code&gt;&amp;lt;regex.h&amp;gt;&lt;/code&gt;，Zig 的 &lt;code&gt;std&lt;/code&gt; 里连这个词都不存在），&lt;strong&gt;有的语言给的是另一套模式语法&lt;/strong&gt;（Lua 的 &lt;code&gt;string.find&lt;/code&gt; 系列是 Lua pattern，没有 &lt;code&gt;|&lt;/code&gt; 交替也没有环视），&lt;strong&gt;剩下的语言才在真正的正则引擎之间分岔&lt;/strong&gt;——一边是回溯引擎（Python、Java、.NET、PHP 的 PCRE2、Ruby 的 Onigmo、JavaScript），功能全但可以被一个嵌套量词写成指数级；另一边是有限自动机的线性时间引擎（Rust 的 &lt;code&gt;regex&lt;/code&gt;、Go 的 &lt;code&gt;regexp&lt;/code&gt;），永远不会被 ReDoS 打穿，代价是彻底放弃反向引用与环视。本页按四个主题组织：&lt;strong&gt;引擎与方言 → 匹配与查找 → 捕获组与替换 → 性能安全与陷阱&lt;/strong&gt;，每个主题一套 18 语言标签页。&lt;/p&gt;</description></item></channel></rss>