说句完全坦白的:如今我写 Go 的量,没有自己希望的那么多。
其中一个原因是,我现在所在的公司不用 Go。我们主要使用 TypeScript;我对它仍然爱恨交织,但公平地说,它确实很适合我们。所以这里不想过多责怪 TypeScript。
我仍在维护一些 Go 项目,因此时不时还是会写一点 Go。
但天啊,我真怀念能多写一些 Go 的日子。
尤其是它的开发体验。对我而言,没有别的语言能接近;有趣的是,我认为在 AI 时代,这一点会变得更加重要。本文就想围绕这个话题稍微吐槽一下。
赞助

AI 写出的代码比以往都多。审查它们不应意味着按字母顺序,在四十个文件间来回滚动。
CodeRabbit Review 会把任意 pull request 从扁平的文件列表重组为结构化、逐层展开的导览:按照变更合乎逻辑的阅读顺序,而不是平台碰巧排出的顺序。每个代码范围都会有自己的通俗摘要;只要可视化确有价值,时序图、状态机和 ERD 都会直接生成在相应位置。
Cohort 会把相关文件和代码片段归为一组,让你一次审查一个概念。Layer 会为它们排序,让基础变更——数据形状、契约——先于依赖它们的代码出现。Code Peek 让你点击任意变量、函数、类或类型,在不离开当前标签页的情况下查看其定义和使用位置;Semantic Diff 视图则略过格式噪音,只呈现真正发生的变化。
直接从 PR Walkthrough 里的 Review Change Stack 按钮打开即可。你可以用键盘在 cohort 和 layer 间导航,针对精确的代码行范围留下评论,并提交原生 review、评论和审批;它们会回写到 GitHub 或 GitLab——就在团队原本使用的平台上。
目前处于早期访问阶段,所有人都可免费使用。
来自率先开创 AI 代码审查的团队:每周 200 万次审查、600 万个仓库、15,000 名客户。一个为现代 PR 实际写作方式而打造的审查界面。
立即使用 CodeRabbit Review 审查你的下一个 PR
随着编程 agent 和写代码的方式出现,事情显然正在改变。顺带说一句,我并不是指所有人;我依然非常尊敬那些不重度依赖 AI、亲手雕琢软件的人。我相信这种程度的工程技艺永远会有空间。
因此,事情正在改变。是变好还是变坏,我还不完全确定;但已经能看到一些趋势在形成。Rust 和 TypeScript 正成为 AI 生成代码的主流选择,而有些其他语言……只能说,你听到它们的次数正越来越少。
真正的问题是:五年后,哪些编程语言仍然重要?
我认为,新项目中动态后端语言会变少:Ruby on Rails、PHP,甚至 Python 在某些后端工作负载中的使用也是如此。这显然不是因为它们不好,其中很多对人类来说都非常出色。
你看,在没有 AI 时,语言很大程度上竞争的是人类工程体验。现在,它们还要竞争机器工程体验。
以 Ruby on Rails 为例。它对人类极其友好,但我会认为,从性能和类型两个角度看,它未必同样适合机器。人类能很自然地驾驭约定、隐式魔法和 DSL,因为人类理解上下文;模型对此更吃力。显式的系统显然更容易让它们推理。
接着是一些所谓的 AI 原生语言。
说实话,我仍不完全理解它们的卖点。两者都像是粗制滥造的 AI 语言,仿佛由这样的提示词生成:“嘿,帮我做一门编程语言,别犯错。”
如今的模型大多在既有语言和既有生态上训练。那么,在没有成熟工具、没有庞大的生产代码库、没有久经实战检验、也几乎没有真实世界数据的一门全新语言里,它们究竟怎么突然就能生成完美代码?
安全性呢?编译呢?这感觉像个黑箱。
所以眼下,生态依然非常重要。
而这正是 Go 变得格外有趣的地方。
因为在我看来——尽管很多人会不同意——Go 对 LLM 来说其实是一门非常好的语言。不只对人类好,对模型也好。说真的,我非常希望它能赢下这场竞争。
下面来看看我认为让 Go 特别适合 agent 时代的几个特点。
首先,标准库规模极大,而且设计得极好。只靠非常少的依赖,就能构建真正的生产系统。HTTP 服务器、JSON 处理、加密、测试、并发、文件系统——大部分都已具备。
还有很重要的一点:Go 团队对安全性和稳定性极其认真。你很少听说 Go 标准库本身引发灾难性的、生态级别的安全事故。
然后是编译器。Go 的编译速度快得惊人。
这在 AI 时代比人们意识到的重要得多。人类可以容忍较慢的反馈循环,agent 真的不行。AI 系统在解决一个任务时,可能要编译并迭代数百次;快速编译会直接改善这种工作流。
此外还有:
单一静态二进制文件分发
内置格式化
强大的交叉编译
几乎没有依赖地狱
简单且刻意朴素的语法
Go 很务实。大多数事情都有一条显而易见的做法
- 这其实是 Go 最伟大的优点之一。Go 有意移除了许多写出“花活”代码的方式。把事情搞乱的路径更少,因此 AI 生成的 Go 代码往往意外地干净且易于维护。
我最喜欢的特性之一,是 Go 的兼容性承诺。
在 Go 1 发布时,团队引入了一项兼容性保证:旧程序应当能在更新的 Go 版本上继续工作。
这听起来很无聊,直到你拿它和一些现代 JavaScript 生态相比:两年前的依赖就已经无法运行了。
我至今仍能打开近十年前写的 Go 项目,在现代 Go 版本上毫无问题地运行。
这种级别的稳定性实在罕见。
我认为,稳定性可能会重新成为最有价值的工程属性之一,尤其是当 AI 开始生成海量代码时。没有人想要数百万行生成代码依赖脆弱的生态,并且每六个月就坏一次。
不妨实际试一下。
我找到一个十年前的旧项目:https://github.com/plutov/games
它直接就能运行。
我还认为,格式化的重要性远比人们承认的更高,尤其是在仍由人类审查 AI 生成代码的时候。
仅 gofmt 就已经带来巨大价值。
每个 Go 项目看起来都大致相同。风格指南基本内建在语言本身。你不用花时间争论格式规则,也不用安装十五个 prettier 插件和 linter 配置。
只要运行:gofmt
当 AI 生成代码时,这种一致性更有价值,因为风格熵几乎不会不断累积。
接着是 go vet 和 lint;它们也能在不同项目之间保持一致。
另一个被严重低估的特性是交叉编译。
它至今仍让我觉得像魔法:
GOOS=windows GOARCH=amd64 go build
GOOS=linux GOARCH=arm64 go build
就这样。
无需搭建复杂的构建流水线或外部工具,你立刻就能得到完全不同平台的二进制文件。
再一次:更少的活动部件。
更少会损坏的东西。
当自主 agent 开始端到端构建和部署系统时,这非常重要。
再说一次错误处理。
有人不喜欢 Go 的错误处理,因为它很冗长;也有人喜欢它,因为它足够显式。
err := os.ReadFile()
if err != nil {
// ...
}
坦白说,对 AI 生成代码而言,显式性非常棒。
控制流一目了然,失败路径清晰可见。隐藏的魔法更少,歧义也更少。代码直接且确定时,模型通常表现得更好。
你几乎被迫去思考失败情形。
而这是一件好事。
还有并发。
Go 依旧拥有有史以来最出色的并发模型之一。
go fetchData()
即使到了今天,相比许多其他生态,在 Go 中启动并发工作仍显得轻得不可思议。
简单的原语,简单的心智模型。
我有一个稍具争议的看法:AI 可能会让“无聊”的语言变得更有价值,而不是更没价值。
因为可维护性的扩展性比聪明才智更好。
生成的代码不需要达到天才级工程水准。它需要可理解、稳定、可重构,并且易于验证。
而 Go 恰好以正确的方式骄傲地保持无聊。
我不知道 Go 会不会成为 AI 时代的主导语言。
也许不会。
但我确实认为它会老得非常好。
Go 依然显得清爽而简单。
说真的,简单性最终可能会成为整个 AI 时代最重要的特性之一。