当 AI 写了你 80% 的代码,语言设计比以往任何时候都重要

为什么 Go 是大模型代码生成的最佳语言
🎭 Rust 的幻象
OpenAI 总裁 Greg Brockman 最近抛出一个大胆的论断:”只要 Rust 能编译通过,它就基本是正确的。” 编译器在代码运行前就能捕获内存错误、生命周期违规和数据竞争。听起来像是 AI 生成代码的完美语言?
开发者 Emil Privér 给出了有力的反驳。当大模型遇到 Rust 复杂的生命周期标注和所有权难题时,它们不会去解决问题——而是作弊。模型会塞入 unsafe {} 块,到处撒 .unwrap(),把所有东西包进 Arc<Mutex<T>>。那些让 Rust 具有吸引力的安全保证,恰恰被试图让编译器通过的 AI 绕了过去。
这不是边缘情况。大模型本质上做的是下一个 token 的概率预测。当概率分布变得复杂——正如 Rust 借用检查器制造的那样——模型会走阻力最小的路径。在 Rust 里,这条路往往直接穿过 unsafe。
📐 什么让一门语言对大模型友好?
要理解 Go 为何出色,我们需要思考大模型生成代码时实际在做什么。它们基于上下文预测最可能的下一个 token。三个特性让这种预测变得显著更容易:
代码同质化。 gofmt 为所有 Go 代码强制执行统一的规范格式。每个 Go 项目看起来都一样。没有大括号位置之争,没有缩进风格之争。对于在数百万 Go 文件上训练的大模型而言,统计模式被强化而非被风格差异稀释。
语法最小化。 Go 只有一种循环结构:for。没有 while,没有 do-while,没有 foreach。错误处理遵循唯一模式:if err != nil { return err }。没有运算符重载,没有宏,没有隐式类型转换。当模型预测 Go 中的下一个 token 时,搜索空间急剧缩小。
低歧义性。 在语法丰富的语言中——模式匹配、trait 实现、生命周期标注、隐式返回——模型必须在许多合法补全之间做选择。在 Go 中,通常只有一种显而易见的写法。模型不需要猜测你的编码风格,因为 Go 实际上只有一种风格。
📊 数据说话
我们可以从经验上观察到这种效应。在跨语言的大模型代码生成基准测试中,Go 始终表现出比 Rust 更高的首次编译通过率。生成的代码能编译、能运行、行为符合预期——不是因为 Go 在贬义上”简单”,而是因为它的设计最小化了预测空间的熵。
考虑一个常见任务:读取文件并处理错误。在 Rust 中,模型需要在 ? 运算符、.unwrap()、.expect()、match 块以及带 From 实现的自定义错误类型之间做选择。在 Go 中:
1 | data, err := os.ReadFile(path) |
本质上只有一种写法。大模型不需要做风格决策。
😴 “无聊”的优势
Go 一直被批评太”无聊”——特性太少,样板代码太多,多年没有泛型。但在 AI 时代,无聊就是超能力。
当 80% 以上的生产代码由 AI 生成——我们正快速走向这一天——语言中最重要的品质发生了根本性转变。”表达力”和”能力”变得不那么重要,”可读性”和”无歧义”变得更重要。一门任何合格的开发者(或 AI)对同一问题都会产生几乎相同代码的语言,意味着:
- 代码审查更快,因为模式可预测
- Bug 更容易发现,因为偏离常规的代码会凸显出来
- AI 生成的代码与人写的代码无缝融合
- 重构工具运行得更可靠
🤔 TypeScript 和 Python 呢?
Python 的缩进敏感性和鸭子类型带来歧义。TypeScript 的类型系统虽然强大,但提供了数十种方式来表达同一个约束。两种语言都有格式化之争,分裂了训练数据。
Go 占据了独特位置:静态类型(给大模型清晰的类型信息用于推理),编译型(在运行前捕获错误),语法统一(最大化预测准确率)。它是 AI 代码生成的甜蜜点。
💡 结语
讽刺的是,Go 在 2007 年由 Rob Pike 和 Ken Thompson 设计时秉持的哲学——“少即是多”——曾让许多开发者感到沮丧。特性被刻意省略,语言被有意约束。当时这像是固执。
将近二十年后,这些约束恰好是大模型所需要的。Go “无聊”的设计——一种循环、一种错误模式、一种格式风格——在所有主流编译型语言中创造了最可预测的 token 分布。
当 AI 编写越来越多的代码时,你认为什么设计哲学更重要——表达力还是可预测性?
评论