阅读视图

发现新文章,点击刷新页面。
🔲 ⭐

Rust 还没进前十,TIOBE 就开始唱衰了?

本文永久链接 – https://tonybai.com/2026/04/17/tiobe-ranking-and-the-decline-of-rust-hype

大家好,我是Tony Bai。

过去几年,技术圈最热门的“猜谜游戏”之一,就是预测 Rust 什么时候能杀入 TIOBE 排行榜的前十。

这门被誉为“天选之子”的语言,连续多年霸榜 Stack Overflow“最受喜爱”的宝座,被微软、亚马逊等巨头奉为重写底层基础设施的“银弹”。所有人都觉得,它冲进前十,只是时间问题。

但就在最近,TIOBE 指数发布了 2026 年 4 月的最新排名。

榜单本身平平无奇,Rust 的排名甚至还从去年同期的 18 位微升到了 今年的16 位。

然而,TIOBE 的 CEO Paul Jansen 亲自撰写的一篇社论,却像一盆冷水,劈头盖脸地浇在了所有 Rustacean(Rust 开发者)的头上。

Paul Jansen 用极其明确的措辞,给这门甚至还没来得及摸到前十门槛的语言,提前下了一份“病危通知书”:

“Rust 的崛起显示出放缓的迹象。……它进入前十的梦想,现在看来比以前更加遥远了。”

这篇社论,瞬间引爆了全网的讨论。

无数 Rust 开发者感到匪夷所思,甚至有些愤怒:我们还没真正发力,你怎么就开始唱衰了?

这背后,到底是 TIOBE 对技术趋势的精准预判,还是这把统治了我们十几年的“认知标尺”,已经彻底失灵了?

今天,我们就来扒开这张榜单的底裤,看看在喧嚣的数据背后,Rust 的真实处境,究竟是怎样的。

官方的“诊断书”:Rust 的“阿喀琉斯之踵”

我们先来看看 TIOBE CEO Paul Jansen 的“诊断报告”。

他指出,Rust 在今年年初曾一度冲到历史最高排名第 13 位,但仅仅三个月后,就又跌回了第 16 位。

他给出的解释是:

“一个可能的解释是,尽管 Rust 能够生产出高效和安全的代码,但对于非专家程序员来说,它仍然难以学习。虽然专家们愿意投入时间去掌握这门语言,但更广泛的主流采用似乎面临着更大的挑战。”

这段话,精准地戳中了 Rust 社区最敏感、也最引以为傲的那根神经——陡峭的学习曲线

为了追求极致的内存安全,Rust 发明了极其复杂的“所有权(Ownership)”和“借用检查(Borrow Checker)”系统。这套系统像一个极其严苛的导师,在你编译代码的每一个环节,都对你进行着灵魂拷问。

无数新手在入门 Rust 时,都会经历一段被称为“与编译器搏斗”的痛苦时期。

TIOBE 的观点很明确:这种“精英主义”的设计哲学,正在成为 Rust “出圈”的最大障碍。

榜单的原罪:用“百度指数”去衡量火箭科学

TIOBE 的诊断听起来似乎很有道理。但我们必须先问一个更底层的问题:TIOBE 指数,到底是个什么东西?

TIOBE 的排名,本质上是一个基于“搜索引擎查询量”的指标。它在全球 25 个主流搜索引擎上,统计包含 +” programming” 关键词的页面数量。

看懂了吗?这套诞生于 十多年前的评判标准,在 2026 年的今天,已经变得极其荒谬

它衡量的是一门语言在公网上的“话题度”和“声量”,而不是它的“真实价值”和“商业应用”。

这就像用“微博热搜”的次数,去评判一位科学家的学术贡献一样可笑。

用这把“旧尺子”去衡量现代编程语言,会产生几个致命的认知偏差:

1. 越是难学、坑越多的语言,排名越高。

这恰恰是 TIOBE 逻辑最诡异的地方。Paul Jansen 一边抱怨 Rust 太难学,一边却忽视了,正是因为“难学”,新用户才会频繁地去 Google 搜索“Rust a lifetime that lives long enough”、“the trait Borrow is not implemented for String”这些令人抓狂的报错信息。

每一次“救命”的搜索,都在为 Rust 的 TIOBE 排名,贡献着宝贵的 KPI。

2. 越是成熟、生态完善的语言,排名越吃亏。

随着一门语言的成熟,它的文档会越来越完善,社区的最佳实践会沉淀下来。开发者遇到的问题,更多地会在官方文档、IDE 提示、或者小圈子的 Slack/Discord 里被解决,而不会产生大量的公开搜索。

没有问题,就没有搜索。没有搜索,就没有 TIOBE 排名。

3. TIOBE 无法衡量“生态位”的价值。

Rust 的江山在哪里?在 Linux 内核里(注:最近发布的Linux Kernel 7.0里,Rust已经正式转正了!),在 Windows 的系统组件里,在 Cloudflare 的边缘网络里,在 Figma 的渲染引擎里,在那些对性能和安全要求达到极致的底层基础设施里。

这些领域的开发者,是金字塔尖的系统程序员。他们讨论问题,是在 GitHub Issue、Zulip 频道,而不是在 CSDN 上问“我的 &mut 为什么传不进去”。

Rust 的价值,深藏在那些不会产生大量公开搜索记录的、高壁垒的硬核场景里。而 TIOBE 的爬虫,可能永远也爬不到那里。

真实的版图:Rust 正在经历一场“青春期的烦恼”

扒开 TIOBE 的“障眼法”,我们该如何客观看待 Rust 在 2026 年的真实处境?

Rust 并没有“增长放缓”,它只是在经历一场必然的“出圈阵痛”。

任何一门新技术的发展,都会经历两个阶段:

  1. 从 0 到 1 的“深耕期”:吸引最硬核、最狂热的一批早期用户,在特定的垂直领域里,将自己的核心优势打磨到极致。Rust 在“系统编程”领域,已经完美地完成了这个阶段。
  2. 从 1 到 N 的“出圈期”:试图将自己的影响力,扩展到更广阔的领域,吸引更多的主流开发者。

Rust 现在正处于从阶段一向阶段二过渡的关键时期。它那套为系统编程量身打造的、极致安全的内存管理哲学,在 Web 开发、数据科学、GUI 应用等场景下,确实给很多开发者带来了巨大的心智负担。

Rust 社区内部,关于是否应该为了“易用性”而牺牲部分“极致性”的争论,也从未停止。比如,关于异步运行时的分裂(Tokio vs async-std)、关于标准库的精简与扩充,都反映了这种“青春期的烦恼”。

Rust 没有停滞,它只是在“成长的十字路口”,在思考自己到底想成为谁。

我们真正应该关注什么?

作为身处一线的工程师,我们应该如何看待 TIOBE 的这份“诊断书”?

第一,永远不要把“流行度”作为技术选型的唯一标准。

JavaScript 很流行,但你不会用它去写操作系统内核。COBOL 极其冷门,但全球的银行系统依然跑在它上面,顶级 COBOL 程序员的薪资高得吓人。

技术的价值,永远取决于它在特定场景下,解决了多大规模、多高难度的商业问题。

第二,警惕“易用性”的陷阱。

Go、Python 很简单。但这种简单,可能是以牺牲“运行时安全保证”(比如Python 的动态类型、Go的Nil指针等)为代价的。

Rust 的“难”,恰恰是把所有可能在深夜引发线上雪崩的风险,全部前置到了编译阶段。它用“编译时的痛苦”,换取了“运行时的安宁”。

这种设计哲学,对于金融交易、底层基础设施、航空航天等“不容有失”的领域来说,是无价之宝。

第三,对自己的成长负责,而不是对榜单负责。

与其每个月焦虑地刷新 TIOBE 的排名,不如去问自己几个更本质的问题:

  • 我所处的行业,未来 3-5 年最核心的技术瓶颈是什么?
  • 为了解决这些瓶颈,我需要掌握哪些不可替代的底层能力?
  • 哪门语言的生态和哲学,与这个方向最契合?

你的技术护城河,从来不是由 TIOBE 的排名决定的,而是由你所处行业以及要解决问题的深度决定的。

小结:你的价值,与榜单无关

TIOBE 的这份榜单,与其说是一份严肃的技术报告,不如说是一场成功的“引流狂欢”。

它用一个看似客观的数据,精准地挑动了每个程序员心中最敏感的那根“身份焦虑”神经。

但作为身处一线的工程师,我们必须保持清醒。

衡量一门技术价值的唯一标准,从来不是它在搜索引擎上的热度,而是它在真实的商业世界里,解决了多大、多复杂、多有价值的问题。

当你在用 Rust 构建着下一代安全操作系统,或者用它重写着公司最核心的交易引擎时,你根本无需关心 TIOBE 上的排名是 16 还是 60。

因为你正在创造的价值,早已不是这些过时的“声量指标”所能衡量的。

你的技术栈没有背叛你,但你的认知,可能会。


今日互动探讨:

你觉得 TIOBE 对 Rust“增长放缓”的判断准确吗?你认为 Rust 陡峭的学习曲线,是它最大的优势,还是最大的障碍?

欢迎在评论区分享你的看法!


还在为“复制粘贴喂AI”而烦恼?我的新专栏 AI原生开发工作流实战 将带你:

  • 告别低效,重塑开发范式
  • 驾驭AI Agent(Claude Code),实现工作流自动化
  • 从“AI使用者”进化为规范驱动开发的“工作流指挥家”

扫描下方二维码,开启你的AI原生开发之旅。


原「Gopher部落」已重装升级为「Go & AI 精进营」知识星球,快来加入星球,开启你的技术跃迁之旅吧!

我们致力于打造一个高品质的 Go 语言深度学习AI 应用探索 平台。在这里,你将获得:

  • 体系化 Go 核心进阶内容: 深入「Go原理课」、「Go进阶课」、「Go避坑课」等独家深度专栏,夯实你的 Go 内功。
  • 前沿 Go+AI 实战赋能: 紧跟时代步伐,学习「Go+AI应用实战」、「Agent开发实战课」、「Agentic软件工程课」、「Claude Code开发工作流实战课」、「OpenClaw实战分享」等,掌握 AI 时代新技能。
  • 星主 Tony Bai 亲自答疑: 遇到难题?星主第一时间为你深度解析,扫清学习障碍。
  • 高活跃 Gopher 交流圈: 与众多优秀 Gopher 分享心得、讨论技术,碰撞思想火花。
  • 独家资源与内容首发: 技术文章、课程更新、精选资源,第一时间触达。

衷心希望「Go & AI 精进营」能成为你学习、进步、交流的港湾。让我们在此相聚,享受技术精进的快乐!欢迎你的加入!

img{512x368}


商务合作方式:撰稿、出书、培训、在线课程、合伙创业、咨询、广告合作。如有需求,请扫描下方公众号二维码,与我私信联系。

© 2026, bigwhite. 版权所有.

🔲 ☆

C++ 社区内部大讨论:新特性到底是“生产力革命”,还是“叠加的复杂性”?

本文永久链接 – https://tonybai.com/2026/04/15/cpp-community-debate-productivity-revolution-vs-complexity

大家好,我是Tony Bai。

如果你把编程语言比作工具,Go 是一把极简的手术刀,精准且克制;Rust 是一套带智能传感器的外骨骼装甲,严苛且安全。

而 C++ 呢?它更像是一把在过去四十年里不断被加挂零件的、超重型复合瑞士军刀。

最开始,它只有刀片和叉子;后来,它加了锯子、剪刀和钳子;再后来,它甚至被塞进了一套显微镜和一支激光笔。在开发者眼里,它是能解决世间一切难题的万能神兵,但也是一个重到让你拿不稳、甚至随时可能切到自己手指的“庞然大物”。

但就在前几天,r/cpp 这个拥有近 10 万 C++开发者的顶级社区里,一篇名为《现代 C++ 是让我们更高效了… 还是更复杂了?》的帖子,引发了一场深度大讨论。

发帖人发出了灵魂拷问:

“C++20/23 给我们带来了 Ranges、协程(Coroutines)、Concepts、Modules……这些新特性真的很酷,我也在用。但我总在想,我们是不是在用这些东西吓跑新人的同时,眼睁睁地看着老代码库永远冻结在 C++98?现代 C++ 对生产力来说,到底是一场革命,还是在原本已经足够复杂的巨兽身上,又叠加了一层复杂性?”

这篇帖子,精准地戳中了每一个 C++ 开发者心中最深的困惑。短短一天,就吸引了上百条充满血泪与思考的评论。

今天,我们就来复盘这场顶级的社区大讨论,看看这柄“瑞士军刀”在疯狂“堆料”的背后,到底藏着怎样的挣扎、分裂与反思。

分裂的社区:C++98 遗老、C++17 中坚与 C++23 先锋的“平行宇宙”

在这场大讨论中,我仿佛看到了 C++ 社区三个泾渭分明的平行宇宙。

宇宙一:永远的 C++98/11 ——“能跑就行,别动!”

评论区里,点赞最高的一派观点,充满了对“存量代码”的敬畏与无奈。

一位开发者吐槽道:

“我在太多项目里因为各种原因被迫使用旧标准,以至于我已经懒得去关心最新的特性了。我感觉很多专业场景就是这样:我们用着‘穴居人 C++’,因为那玩意儿安全(指熟悉)、方便。”

另一位开发者更是直接引用了 Matt Godbolt 的名言:“向后兼容性才是 C++ 的超能力。”

“别想着重构了,那只会破坏一切。跑了 20 年没 Bug 的生产代码是无价之宝,别碰它!”

更有甚者,因为芯片厂商的编译器只支持 C++89,或者因为“法律原因”,一个项目被迫在一个 3 年前的工具链上锁死 7 年。

在这个宇宙里,C++20 的新特性,对他们来说都像火星科技一样遥远。

宇宙二:拥抱 C++20/23 ——“旦用难回,太香了!”

与“遗老派”形成鲜明对比的,是那些已经吃上新标准红利的“先锋派”。

有开发者激动地表示:

“自从我开始用协程(Coroutines)写网络 IO 代码,我再也回不去以前那种回调地狱了!”

另一位则对 C++23 的 std::println 赞不绝口:

“我离不开 C++23,完全是因为 println。我不知道我还在用 23 的什么其他特性,但光这一个就太棒了。”

对于这部分开发者来说,现代 C++ 的每一个新特性,都是一次生产力的解放。他们就像一群拿到了新玩具的孩子,兴奋地探索着 Ranges 的组合魔法和 Concepts 带来的清爽报错。

宇宙三:爱恨交织的“中间派”——“一半是天堂,一半是地狱”

这或许是最大多数 C++ 开发者的真实写照。

正如帖子作者所言,新特性确实很酷,但它们也带来了巨大的认知负荷和决策成本。

一个开发者的评论获得了 82 个高赞:

“我们大多数人只用了 C++ 语言特性的一小部分。这就像一个‘鸡生蛋、蛋生鸡’的问题:这里有个新特性,但我不知道该怎么用、为什么要用;或者,我代码里有个痛点,可能能用新特性解决,但我不知道该用哪个。”

这种“选择的困境”,正是 C++ “自由”的代价。

底层矛盾:C++ 的“集市”哲学 vs 团队的“教堂”困境

为什么 C++ 会演变成今天这样?

评论区里的一位开发者给出了一个极其精妙的比喻:“集市(Bazaar)”

“我绝对热爱 C++ 的一点是:它有一个特性集市,你可以挑选你认为适合你项目的工具。如果你看其他语言,比如 Java 要求万物皆对象,Haskell 要求万物皆函数。C++ 给了你面向对象,你讨厌它?没问题,不用就行。你喜欢函数式?C++ 也支持。”

这种“万物皆可选”的自由,是 C++ 最大的魅力,当然也是它最大的诅咒。

因为在一个团队里,当每个人都从“集市”上拿回了自己最喜欢的锤子时,整个项目就会变成一个风格迥异的“建筑工地”。

原帖作者自己也承认:

“自由是真实的,但这也意味着两个 C++ 代码库可能看起来像两种完全不同的语言。”

当一个文件里还在用裸指针和手动内存管理,而另一个文件里已经用上了 std::unique_ptr 和 std::span;当一部分团队在用 boost::asio 写回调,而另一部分团队在用 C++20 的协程……

Code Review 就变成了一场噩梦。

反思:“技术债”还是“护城河”?

这场大讨论的背后,其实隐藏着两个更深层次的软件工程哲学问题。

问题一:新特性是“锦上添花”,还是“非用不可”?

很多 C++ 老兵认为,现代 C++ 增加的很多特性,比如 Ranges 和 Coroutines,其实早在几十年前的 LISP 语言里就已经被证明是伟大的思想。C++ 只是在用一种极其缓慢、极其复杂的方式,在“偿还”几十年前欠下的“技术债”。

但另一些人认为,C++ 的伟大恰恰在于,它能用“零成本抽象(Zero-cost Abstraction)”的硬核方式,将这些高级思想,落地到对性能要求极致的生产环境中。

问题二:复杂性是“敌人”,还是“朋友”?

一位开发者的评论极具辩证思维:

“这(新特性)既是好事,也是坏事。学习的门槛确实在不断提高。但这些工具是实实在在有用的,它们让你能用更干净、更安全、更高效的方式表达代码。”

当 Go在极力做“减法”,试图降低开发者的心智负担时,C++ 却似乎在坚定地走着另一条路:它信任开发者是专家,它把所有的选择权和复杂性都交给你,让你自己去构建属于你的“最佳子集”。

这就像驾驶一架拥有几百个仪表盘的航天飞机。对于新手来说是灾难,但对于顶尖的飞行员来说,每一个按钮都意味着更精准的控制力。

出路何在?:拥抱“渐进式现代化”

在这场看似无解的“内部大讨论”中,我们依然能找到一条充满智慧的中间路线。

有人分享了一个极具参考价值的真实案例:

他成功地在一个庞大的 C++98 代码库中,引入了一个用 C++17 编写的新功能模块。他没有去重构任何老代码,只是简单地升级了编译器和构建脚本。结果:新特性带来了性能的提升和开发效率的飞跃,而老代码依然稳定运行。

这或许就是现代 C++ 正确的打开方式:不要试图用新标准去“革命”旧代码,而是在写新代码时,大胆地、有选择地拥抱新特性。

让 C++98 的归 C++98,让 C++23 的归 C++23。在一个代码库中,允许不同时代的“方言”共存,用新增的模块去逐步“稀释”历史的包袱。

小结:一场关于“自由”的伟大实验

C++ 的这场大讨论,没有赢家。

它只是再次向我们证明了这门语言的“独一无二”:它是一门民主的语言。它给了你选择一切的自由,也要求你为自己的选择承担一切后果。

用一位开发者的话来说:

“Rust 强加给你它的观点;而 C++ 要求你有你自己的观点。这就像专制与民主的区别。大多数时候,民主只是一个被猴子笼子管理的、组织混乱的马戏团。但我更喜欢民主。

或许,对于我们这些已经习惯了 Go 和 Rust 那种“带你走”模式的开发者来说,偶尔回头看看 C++ 这个充满“混沌与活力”的古老集市,会让我们对“软件工程”这门手艺,有更深刻的理解。

资料链接:https://www.reddit.com/r/cpp/comments/1sihs1w/is_modern_c_actually_making_us_more_productive_or


今日互动探讨:

在你的技术生涯中,你是否也曾被困在某个古老的“技术版本”里动弹不得?对于 C++ 这种“万物皆可选”的自由哲学,你是向往,还是恐惧?

欢迎在评论区分享你的看法!


还在为“复制粘贴喂AI”而烦恼?我的新专栏 AI原生开发工作流实战 将带你:

  • 告别低效,重塑开发范式
  • 驾驭AI Agent(Claude Code),实现工作流自动化
  • 从“AI使用者”进化为规范驱动开发的“工作流指挥家”

扫描下方二维码,开启你的AI原生开发之旅。


原「Gopher部落」已重装升级为「Go & AI 精进营」知识星球,快来加入星球,开启你的技术跃迁之旅吧!

我们致力于打造一个高品质的 Go 语言深度学习AI 应用探索 平台。在这里,你将获得:

  • 体系化 Go 核心进阶内容: 深入「Go原理课」、「Go进阶课」、「Go避坑课」等独家深度专栏,夯实你的 Go 内功。
  • 前沿 Go+AI 实战赋能: 紧跟时代步伐,学习「Go+AI应用实战」、「Agent开发实战课」、「Agentic软件工程课」、「Claude Code开发工作流实战课」、「OpenClaw实战分享」等,掌握 AI 时代新技能。
  • 星主 Tony Bai 亲自答疑: 遇到难题?星主第一时间为你深度解析,扫清学习障碍。
  • 高活跃 Gopher 交流圈: 与众多优秀 Gopher 分享心得、讨论技术,碰撞思想火花。
  • 独家资源与内容首发: 技术文章、课程更新、精选资源,第一时间触达。

衷心希望「Go & AI 精进营」能成为你学习、进步、交流的港湾。让我们在此相聚,享受技术精进的快乐!欢迎你的加入!

img{512x368}


商务合作方式:撰稿、出书、培训、在线课程、合伙创业、咨询、广告合作。如有需求,请扫描下方公众号二维码,与我私信联系。

© 2026, bigwhite. 版权所有.

🔲 ☆

当 Go 还在追求极简时,C++ 26 却又加了四大“史诗级”新特性

本文永久链接 – https://tonybai.com/2026/03/31/go-minimalism-vs-cpp26-epic-new-features

大家好,我是Tony Bai。

在这个 Go、Zig 等“小而美”新语言颇受青睐的时代,如果你去技术社区里问一句:“C++ 这门语言怎么样?”

你大概率会得到一堆充满戏谑的回答:“太复杂了,别学”、“从入门到放弃”、“面试造火箭,工作拧螺丝”。

C++,这门诞生于上世纪 80 年代的编程语言,似乎早已被贴上了“老旧、臃肿、极其反人类”的标签。在很多新生代开发者眼里,它就像一头步履蹒跚的史前巨兽,理应被时代所淘汰。

但就在前天(2026年3月29日),这头“史前巨兽”不仅没有倒下,反而亮出了它那足以撕裂天空的獠牙。

C++ 标准委员会主席、C++ 界的“教父级”人物 Herb Sutter 亲自在博客上宣布:C++26 标准的技术工作,已正式完成!

Herb Sutter 还用极其兴奋的口吻将其定义为“自 C++11 以来最具冲击力的一次发布”。而这次更新的核心,是四个被他称为“Fab Four”(神奇四侠)的史诗级新特性。

当我耐着性子看完全部内容后,我脑子里只剩下四个字:叹为观止。

当 Go 语言的开发者还在为“是否要给语言增加一个三元表达式”,或泛型方法而激烈辩论时,C++ 却反其道而行之,给自己又加装了四门“宇宙级”的重型武器。这到底是 C++ 吹响的绝地反击号角,还是压垮骆驼的最后一根稻草?

今天,我们就来硬核扒开 C++26 这四大“金刚”,看看它们到底有多强,以及它们将如何影响将来程序员对编程语言的选择。

第一门重炮:反射(Reflection)——“代码生成代码”的终极魔法

Herb Sutter 将反射放在了四大特性之首,并称之为“自模板(Templates)发明以来 C++ 最重要的升级”。

什么是C++ 的反射?简单来说,就是让代码在编译期拥有了“自我审视”和“自我创造”的能力。

在 C++26 之前,如果你想实现一个通用的 JSON 序列/反序列化库,你必须写大量重复的模板代码,或者用各种丑陋的宏来“欺骗”编译器。

但在 C++26 中,你可以像这样写出充满“神性”的代码(代码示意):

这段代码,在编译的时候就能根据编译时的输入(test.json)自动分析JSON构造,并生成编译时用于计算的一个新类型。这在 Go 语言里,需要借助 reflect 包在运行时(Runtime)以牺牲性能为代价才能做到。而 C++,直接在静态编译期(Compile-time)零成本搞定了!

Herb Sutter 将其形容为“C++ 的十年火箭引擎”。这意味着,未来 C++ 社区将涌现出无数极其强大、但又极其复杂的元编程(Metaprogramming)库。C++ 的学习曲线,将再次被拉到一个新的高度。

第二道防线:内存安全(Memory Safety)——“只需重编,安全自来”

如果说反射让 C++ 的上限变得更加遥不可及,那么内存安全的提升,则是 C++ 在向 Go 和 Rust 的核心优势区发起的正面冲锋。

C++ 常年被诟病的核心痛点是什么?内存不安全。悬垂指针、未初始化变量读取(导致未定义行为)……这些噩梦困扰了 C++ 程序员几十年。

C++26 给出了一个极其诱人的承诺:你的老代码一行都不用改,只要用 C++26 模式重新编译,就能自动获得大幅度的安全提升!

这主要来源于两个方面的改进:

  1. 消灭未初始化变量的 UB:在 C++26 中,读取未初始化局部变量不再是“未定义行为(Undefined Behavior)”。这意味着困扰无数新手的、极其诡异的程序崩溃,将成为历史。
  2. “加固”的标准库:Google 和 Apple 已经将它们内部经过“加固(Hardened)”的标准库实现贡献给了 C++26。这意味着,当你使用 std::vector, std::string 等容器时,大量的边界检查会自动开启。

Herb Sutter 引用了 Google 的内部数据:

“仅在 Google,这项技术就已经修复了超过 1000 个 Bug,预计每年可以预防 1000 到 2000 个新 Bug 的产生,并将整个生产环境的段错误(Segfault)率降低了 30%。”

这简直是在对 Go 说:“你用 GC 换来的那点可怜的安全性,我 C++ 现在也能做到了,而且依然是零成本的!”

第三把利剑:契约(Contracts)——代码里的“法律条文”

如果你写过 Go,你一定对满屏的 if param == nil { return errors.New(…) } 感到厌烦。这种防御性编程,虽然有效,但极其啰嗦。

C++26 正式引入了语言级的契约编程

你可以像签合同一样,为你的函数制定严格的法律条文:

这些 pre 和 post 是编译器和运行时可以理解并强制执行的“法律”。如果调用者违反了前置条件,程序可以在开发阶段就立刻崩溃并给出明确的报错,而不是等到数据被污染后才在某个奇怪的地方爆炸。

虽然 Go 社区也在讨论类似的泛型断言,但 C++26 已经先行一步,将其做成了语言标准。

第四个引擎:std::execution——C++ 的“亲儿子”协程模型

在 C++20 中,虽然引入了 co_await 协程,但它只是一个语法糖,并没有提供一个统一的调度框架。

C++26 终于补上了这块短板,正式推出了 std::execution,也被称为 Sender/Receiver 模型

这是一个极其强大、统一的异步模型框架。它让你能以一种声明式的方式,去描述、组合和调度复杂的并发任务流。

下面是一段使用std::execution的代码示例:

// This is an example of a custom algorithm for starting work
// without allocations. This algorithm is also available in
// <exec/start_now.hpp>. (Users that don't write custom sender
// algorithms will not need to use receivers or call connect
// or start.)
template <stdexec::sender_in<stdexec::empty_env> Sender>
struct start_now {
  start_now(Sender sndr)
    : _op(stdexec::connect(std::move(sndr), _sink_rcvr())) {
    stdexec::start(_op);
  }
private:
  // start_now is implemented in terms of this custom receiver,
  // which is used to discard Sender's results.
  struct _sink_rcvr {
    using receiver_concept = stdexec::receiver_t;
    void set_value(auto&&...) noexcept {}
    void set_error(auto&&) noexcept {}
    void set_stopped() noexcept {}
  };
  stdexec::connect_result_t<Sender, _sink_rcvr> _op;
};

int main() {
  // A run loop is a fifo queue of work and a loop to execute the
  // work. It needs to be driven by calling its .run() member fn.
  stdexec::run_loop ctx;
  auto event_loop = ctx.get_scheduler();

  // Create two tasks that cooperatively multitask.
  auto task1 = stdexec::just()
             | stdexec::then([]{ std::puts("hello from task 1! suspending..."); })
             | stdexec::continue_on(event_loop) // suspend
             | exec::repeat_n(5)
             | stdexec::then([]{ std::puts("task 1 is done!"); });

  auto task2 = stdexec::just()
             | stdexec::then([]{ std::puts("hello from task 2! suspending..."); })
             | stdexec::continue_on(event_loop) // suspend
             | exec::repeat_n(8)
             | stdexec::then([]{ std::puts("task 2 is done!"); });

  // Start both tasks. This enqueues them for execution on the run loop.
  auto op1 = start_now(stdexec::start_on(event_loop, std::move(task1)));
  auto op2 = start_now(stdexec::start_on(event_loop, std::move(task2)));

  ctx.finish(); // tell the run loop to stop when the queue is empty
  ctx.run();    // tell the run loop to start executing work in the queue
}

这可以被看作是 C++ 对 Go 的 Goroutine + Channel 模型,以及 Rust 的 async/await + tokio 模型的终极回应。

它让 C++ 开发者第一次拥有了一套语言原生的、能够轻松编写“无数据竞争(Data-race-free by construction)”并发程序的“亲儿子”工具。

小结:一场没有退路的豪赌

反射、安全、契约、并发。C++26 的这四大金刚,每一个都足以在其他语言中引发一场大地震。

我们看到的是一头苏醒的巨兽。它没有选择像 Go 那样“断舍离”,也没有像 Rust 那样“偏执于安全”,而是极其贪婪地选择了:“我全都要!”

它既想要极致的表达能力和零成本抽象(反射、模板),又想要与 Rust 媲美的内存安全(加固标准库),还想要不输 Go 的并发表达力(std::execution)。

C++26 给老兵们提供了前所未有的强大武器,但也把本就陡峭的学习曲线,又向上抬升了一个令人惊叹的高度,宇宙第一复杂的编程语言,实至名归!

当 Go 的开发者还在为“是否要加个三元表达式”而争论不休时,C++ 已经头也不回地奔向了“万神殿”。

或许,编程语言的终局,真的不是“大一统”,而是“两极分化”:一极是像 Go 一样追求极致简单的“工程师语言”;而另一极,则是像 C++ 这样,专为那 1% 的、追求极致性能和控制力的“宗师级”开发者准备的、布满荆棘的封神之路。

C++26,欢迎来到神的世界,也欢迎来到神的炼狱。

参考资料

  • https://herbsutter.com/2026/03/29/c26-is-done-trip-report-march-2026-iso-c-standards-meeting-london-croydon-uk/
  • https://herbsutter.com/2025/06/21/trip-report-june-2025-iso-c-standards-meeting-sofia-bulgaria/
  • https://herbsutter.com/2024/07/02/trip-report-summer-iso-c-standards-meeting-st-louis-mo-usa/
  • https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2025/p2996r13.html
  • https://www.youtube.com/watch?v=7z9NNrRDHQU
  • https://www.youtube.com/watch?v=oitYvDe4nps

今日互动探讨:

看完 C++26 的这四大“神仙”特性,你是感到兴奋,还是感到了深深的绝望?你觉得 C++ 的这种“大而全”的演进路线是对的,还是 Go 的“小而美”更代表未来?

欢迎在评论区分享你的看法!


还在为“复制粘贴喂AI”而烦恼?我的新专栏 AI原生开发工作流实战 将带你:

  • 告别低效,重塑开发范式
  • 驾驭AI Agent(Claude Code),实现工作流自动化
  • 从“AI使用者”进化为规范驱动开发的“工作流指挥家”

扫描下方二维码,开启你的AI原生开发之旅。


你的Go技能,是否也卡在了“熟练”到“精通”的瓶颈期?

  • 想写出更地道、更健壮的Go代码,却总在细节上踩坑?
  • 渴望提升软件设计能力,驾驭复杂Go项目却缺乏章法?
  • 想打造生产级的Go服务,却在工程化实践中屡屡受挫?

继《Go语言第一课》后,我的《Go语言进阶课》终于在极客时间与大家见面了!

我的全新极客时间专栏 《Tony Bai·Go语言进阶课》就是为这样的你量身打造!30+讲硬核内容,带你夯实语法认知,提升设计思维,锻造工程实践能力,更有实战项目串讲。

目标只有一个:助你完成从“Go熟练工”到“Go专家”的蜕变! 现在就加入,让你的Go技能再上一个新台阶!


商务合作方式:撰稿、出书、培训、在线课程、合伙创业、咨询、广告合作。如有需求,请扫描下方公众号二维码,与我私信联系。

© 2026, bigwhite. 版权所有.

🔲 ☆

OpenAI 创始人盛赞 Rust,却遭开发者反驳:Go 才是大模型眼里的“香饽饽”!

本文永久链接 – https://tonybai.com/2026/03/23/go-is-the-best-programming-language-for-llm

大家好,我是Tony Bai。

在这个大模型重塑编程范式的当下,如果你想开发一个自主运行的智能体(Agent),或者想让大模型(LLM)帮你生成上万行的核心业务代码,你会选择哪门编程语言?

如果你去问 OpenAI 的总裁兼联合创始人 Greg Brockman,他的答案非常直接:

“Rust is a perfect language for agents, given that if it compiles it’s ~correct.”
(Rust 是开发 Agent 的完美语言,因为只要它能编译通过,它就基本是正确的。)

这句话听起来极其硬核且有道理。Rust 引以为傲的所有权模型和严苛的编译器,就像一个极度刻薄的审查员。既然大模型经常“胡言乱语”,那不如交给 Rust 编译器来兜底。

但有趣的是,Greg 的这番高论,最近在推特(X)上遭到了不少一线资深开发者的强烈反驳。其中,一条阅读量近 7 万的推文直指核心痛点,甚至抛出了一个让无数 Gopher(Go 开发者)极度舒适的反直觉结论:

“别吹 Rust 了,在大模型眼里,语法简单、风格统一的 Go 才是真正的‘香饽饽’!”

今天,我们就来扒一扒这场顶级“语言战争”背后的神仙打架,看看为什么 Go 语言身上那些曾经被全网群嘲的“缺点”,如今却成了大模型时代最无敌的护城河。

大模型写 Rust,真的安全吗?

发起反驳的开发者 Emil Privér 一针见血地指出了用大模型写 Rust 的最大陷阱:“逃课”心理

Greg Brockman 认为 Rust 编译器能阻止大模型犯错。但这有一个前提:大模型必须老老实实地去解生命周期(Lifetime)和所有权(Ownership)的方程。

然而现实是,大模型也是会“偷懒”的。

Emil 敏锐地指出,当现代 LLM 在生成复杂的 Rust 业务逻辑,且实在绕不过编译器的各种借用检查报错时,它们会极其鸡贼地使出大招:直接套上一层 unsafe {} 块,或者无脑使用 .unwrap() 来强行绕过编译器的安全审查!

你在指望编译器兜底,大模型却在底下悄悄开了“后门”。

就像评论区一位开发者吐槽的那样:“当你看到大模型为了图省事,把一段关键操作包在 unsafe 里,并且依然能顺利编译通过时,你还敢说它‘只要编译通过就基本正确’吗?”

虽然有开发者反驳说,可以通过配置强制禁止 unsafe。但大模型的“逃课手段”防不胜防,比如疯狂滥用 RefCell 导致运行时 Panic,这在编译器眼里是合法的,但在生产环境下却是灾难。

Go 的“无趣”,成了最顶级的生产力

既然 Rust 太“聪明”导致大模型容易弄巧成拙,那大模型到底喜欢什么样的语言?

Emil 给出的答案是:Go。

他的底层逻辑非常硬核。

他认为,大模型(LLMs)的本质是基于大量预训练语料进行下一个 Token 的概率预测。对于这种预测机制来说,一段代码的上下文看起来越“同质化(Looks the same)”,大模型生成的准确率就越高。

这就牵扯到了 Go 语言一个常年被群嘲的“缺点”:啰嗦、缺乏表现力、没有花里胡哨的语法糖。

在 Go 里,如果你想写一个循环,你只有一种办法:for 循环。

没有 while,没有 do-while,没有 foreach,更没有各种炫技的函数式流处理。

而在 Rust 或者 JavaScript 等语言里,你想遍历一个数组,至少有 5 种写法。甚至在不同的开源库里,大家的编码风格都千奇百怪。

在人类看来,Go 语言简直“无趣”到了极点。但在大模型这种无情的“概率预测机器”眼里,Go 简直就是天堂!

因为 Go 语言有着近乎暴君般的强制格式化工具 gofmt,以及全宇宙最少、最没有歧义的语法关键字。无论你是 Google 的顶级工程师,还是刚入门三个月的新手,写出来的 Go 代码结构几乎是一模一样的。

这种极度“收敛”和“无聊”的代码风格,恰恰完美契合了大模型的预测机制。

当所有的 Go 项目看起来都像是一个模子里刻出来的,大模型在生成上下文时就不需要去猜测“这个项目的主人喜欢用哪种流派”。它闭着眼睛往下预测,准确率就能轻易碾压其他语言。

Go,这种“一眼望到底”的特性,让它成为了大模型眼里的头号“香饽饽”。

AI 时代的软件工程师,该选什么语言?

推特评论区里,争论依然在继续。

但透过这场口水战,我们作为一线的软件工程师,应该看透一个更深层次的时代演进:

在过去十年,程序员们热衷于发明各种奇技淫巧,比拼谁的代码写得更短、更具“魔法”;但在未来,当 80%以上 的代码都将由 AI Agent 自动生成时,“可读性”与“无歧义”将成为一门编程语言最核心的生产力。

Go 语言的联合缔造者 Rob Pike 当年顶着巨大的压力,坚持不给 Go 加各种复杂的特性。很多人觉得他固执、老派。但在十多年后的今天,当大模型海啸席卷而来时,我们才突然惊觉:

Go 语言那种“强迫你用最笨、最直白的方式写代码”的设计哲学,不仅让它在微服务时代大杀四方,更让它在 AGI 时代,成为了大模型最忠实、最可靠的合作伙伴。

当大模型吐出一段复杂的 Rust 代码,你可能还要花十分钟去审查它有没有隐藏的逻辑陷阱;

但当大模型吐出一段 Go 代码,那满屏极其直白的 if err != nil,让人类工程师一眼就能看穿它的核心逻辑。

没有魔法,才是大模型时代最强的防御。

资料链接:https://x.com/emil_priver/status/2034971247348535399


今日互动探讨:

在日常开发中,你让 ChatGPT/Claude 帮你写过哪种语言的代码?你觉得它写 Go、Python 还是 Rust 时的准确率最高?

欢迎在评论区分享你的实战感受!


还在为“复制粘贴喂AI”而烦恼?我的新专栏 AI原生开发工作流实战 将带你:

  • 告别低效,重塑开发范式
  • 驾驭AI Agent(Claude Code),实现工作流自动化
  • 从“AI使用者”进化为规范驱动开发的“工作流指挥家”

扫描下方二维码,开启你的AI原生开发之旅。


你的Go技能,是否也卡在了“熟练”到“精通”的瓶颈期?

  • 想写出更地道、更健壮的Go代码,却总在细节上踩坑?
  • 渴望提升软件设计能力,驾驭复杂Go项目却缺乏章法?
  • 想打造生产级的Go服务,却在工程化实践中屡屡受挫?

继《Go语言第一课》后,我的《Go语言进阶课》终于在极客时间与大家见面了!

我的全新极客时间专栏 《Tony Bai·Go语言进阶课》就是为这样的你量身打造!30+讲硬核内容,带你夯实语法认知,提升设计思维,锻造工程实践能力,更有实战项目串讲。

目标只有一个:助你完成从“Go熟练工”到“Go专家”的蜕变! 现在就加入,让你的Go技能再上一个新台阶!


原「Gopher部落」已重装升级为「Go & AI 精进营」知识星球,快来加入星球,开启你的技术跃迁之旅吧!

我们致力于打造一个高品质的 Go 语言深度学习AI 应用探索 平台。在这里,你将获得:

  • 体系化 Go 核心进阶内容: 深入「Go原理课」、「Go进阶课」、「Go避坑课」等独家深度专栏,夯实你的 Go 内功。
  • 前沿 Go+AI 实战赋能: 紧跟时代步伐,学习「Go+AI应用实战」、「Agent开发实战课」、「Agentic软件工程课」、「Claude Code开发工作流实战课」、「OpenClaw实战分享」等,掌握 AI 时代新技能。
  • 星主 Tony Bai 亲自答疑: 遇到难题?星主第一时间为你深度解析,扫清学习障碍。
  • 高活跃 Gopher 交流圈: 与众多优秀 Gopher 分享心得、讨论技术,碰撞思想火花。
  • 独家资源与内容首发: 技术文章、课程更新、精选资源,第一时间触达。

衷心希望「Go & AI 精进营」能成为你学习、进步、交流的港湾。让我们在此相聚,享受技术精进的快乐!欢迎你的加入!

img{512x368}


商务合作方式:撰稿、出书、培训、在线课程、合伙创业、咨询、广告合作。如有需求,请扫描下方公众号二维码,与我私信联系。

© 2026, bigwhite. 版权所有.

🔲 ☆

真相调查:Go 语言真的消灭了 Undefined Behavior 吗?

本文永久链接 – https://tonybai.com/2026/03/16/go-language-eliminated-undefined-behavior-truth-investigation

大家好,我是Tony Bai。

在系统编程的古老传说中,流传着一个关于“鼻恶魔”(Nasal Demons)的笑话。

这个梗源自 comp.std.c 新闻组,它是对 C/C++ 语言中“未定义行为”(Undefined Behavior,以下简称 UB)最生动也最恐怖的诠释。根据 ISO C++ 标准,如果你的代码触犯了 UB(例如数组越界、有符号整数溢出、空指针解引用),编译器可以“为所欲为”。

这种“为所欲为”不仅包括程序崩溃,还包括产生错误的结果、损坏数据,甚至——虽然只是笑话——让恶魔从你的鼻孔里飞出来。换句话说,一旦触碰 UB,程序的所有保证瞬间失效。

2009 年,Go 语言横空出世,高举“云原生时代系统语言”的旗帜,承诺提供比 C++ 更高的安全性、更快的编译速度和更简单的并发模型。Go 的拥趸们津津乐道于它的内存安全特性,仿佛 Go 已经彻底终结了 UB 的噩梦。

但真相果真如此吗?

近日,我翻阅了一份珍贵的历史资料——2013 年发生在 golang-nuts 邮件组的一场深度辩论。对话的一方是 Go 语言曾经的顶级贡献者 Dave Cheney,另一方是 Go 核心团队成员、gccgo 的作者 Ian Lance Taylor。

这场发生在这个语言童年时期的对话,揭示了一个令人背脊发凉又引人深思的事实:Go 并没有完全消灭未定义行为,它只是将 UB 赶进了一个更隐秘、更危险的角落——并发。

本文将带你层层剥开 Go 语言规范的表皮,调查“未定义行为”在 Go 中的真实生存状态,并探讨这对我们编写高质量代码意味着什么。

用“定义”换取“安全”——Go 的显式哲学

要理解 Go 做了什么,我们首先得明白 C/C++ 为什么保留 UB。Ian Lance Taylor 指出,C/C++ 保留 UB 本质上是为了性能——允许编译器假设“坏事永远不会发生”,从而进行激进的优化。

Dave Cheney 的疑问直击灵魂:“Go 规范中几乎看不到‘undefined’这个词,这种设计如何影响了 Go 的安全性与性能?”

答案是:Go 选择了一条确定性(Determinism)优先的道路。Go 语言规范以一种近乎偏执的态度,将绝大多数在 C/C++ 中属于 UB 的行为,都进行了严格的“定义”。即便是在错误场景下,Go 也要保证行为是可预测的

整数溢出的“确定性”承诺

在 C 语言中,有符号整数(Signed Integer)的溢出是经典的 UB。编译器有权假设溢出永远不会发生,从而将 x + 1 > x 优化为恒真(Always True),这曾导致过无数的安全漏洞。

但在 Go 语言规范中,对此有着截然不同的定义:

无符号整数:运算结果严格按照 2^n 取模。这意味着高位被丢弃,程序可以依赖这种“回绕(Wrap-around)”行为。

有符号整数:运算可以合法地溢出(legally overflow)。结果由有符号整数的表示方式(通常是补码)、运算类型和操作数确定性地定义。溢出不会导致运行时 Panic。

最关键的是,Go 规范明确禁止编译器进行危险的假设:“编译器不得假设溢出不会发生。例如,它不得假设 x < x + 1 总是为真。”

代码实证:

// https://go.dev/play/p/5CZVVU-SITX
package main

import "fmt"

func main() {
    // 1. 有符号整数溢出 (Signed Overflow)
    var a int8 = 127
    // 在 C 语言中这是 UB,但在 Go 中这是明确定义的
    b := a + 1
    fmt.Printf("int8: %d + 1 = %d\n", a, b)
    // 输出: 127 + 1 = -128 (确定性的回绕)

    // 2. 编译器禁止做的优化
    // 如果编译器假设溢出不发生,它会把这个判断优化掉
    if b < a {
        fmt.Println("发生溢出:b 确实小于 a")
    } else {
        fmt.Println("未发生溢出逻辑(Go 中不会走到这里)")
    }

    // 3. 无符号整数溢出 (Unsigned Overflow)
    var c uint8 = 255
    d := c + 1
    fmt.Printf("uint8: %d + 1 = %d\n", c, d)
    // 输出: 255 + 1 = 0 (严格的 Modulo 2^n)
}

Go这么做的代价是Go 编译器失去了一些数学优化机会(例如不能简单地消除某些循环边界检查)。但也消除了因编译器“自作聪明”而导致的逻辑崩塌,保证了不同平台下的行为一致性。

数组越界的“必杀令”

缓冲区溢出(Buffer Overflow)是网络安全史上最大的杀手。C/C++ 将越界访问视为 UB,允许攻击者通过越界读取敏感内存或覆盖返回地址,进而控制系统。

Go 对此零容忍:越界必须触发 Panic。

无论是在栈上分配的数组,还是在堆上分配的切片,Go 编译器都会在每一次访问操作前(除非能静态证明安全)插入一段 Bounds Check(边界检查)指令。一旦越界,程序立即停止,绝不含糊。

代码实证:

// https://go.dev/play/p/-CqDpIDr0BC
package main

import "fmt"

func main() {
    // 定义一个长度为 3 的切片
    s := []int{1, 2, 3}

    // 模拟一个动态索引(避免编译器在编译期直接报错)
    index := getIndex() 

    fmt.Println("尝试访问索引:", index)

    // 这里会触发 Runtime Panic
    // 错误信息明确:runtime error: index out of range [3] with length 3
    val := s[index] 

    fmt.Println("这行代码永远不会执行", val)
}

func getIndex() int {
    return 3
}

这种边界检查是在运行时(Runtime)介入,抛出 Panic,打印堆栈信息。因此会带来运行时性能损耗。虽然现代 Go 编译器引入了 BCA(边界检查消除)技术,但在无法静态分析的场景下,这就是必须缴纳的“安全税”。

空指针的“硬着陆”

在 C 语言中,解引用一个空指针是 UB。编译器有时会优化掉判空逻辑,因为它认为“既然你解引用了,那指针肯定不为空”,导致后续的安全检查失效。

Go 规定:解引用 nil 指针必须触发 Panic。

这通常是通过 CPU 的硬件异常(SIGSEGV)来捕获的。Go 运行时会接管这个硬件信号,并将其转化为一个可恢复的 Go Panic,而不是让进程直接 Core Dump 或进入不可预测的僵死状态。

代码实证:

// https://go.dev/play/p/hlyZks1dGRf
package main

import "fmt"

type User struct {
    Name string
}

func main() {
    var u *User // u 默认为 nil

    fmt.Println("准备访问 nil 指针...")

    // 在 C 中这是 UB,可能导致程序崩溃或更糟的情况
    // 在 Go 中,这不仅会 Panic,还可以被 Recover 捕获
    defer func() {
        if r := recover(); r != nil {
            fmt.Println("捕获到恐慌:", r)
            // 输出: runtime error: invalid memory address or nil pointer dereference
        }
    }()

    // 触发 Panic
    fmt.Println(u.Name)
}

综上,我们可知:在单线程维度,Go 确实几乎消灭了 Undefined Behavior。它通过强制规定行为(Wrapping, Panicking),将“未定义”变成了“定义明确的错误”。即使程序写错了,它的错误方式也是确定的,而非随机的。

房间里的大象——数据竞争

如果文章到这里结束,那么 Go 就是一个完美的、绝对安全的语言。

但 Ian Lance Taylor 随后抛出了一个重磅炸弹:

“However, Go does have undefined behavior: if your program has a race condition, the behaviour is undefined.”
(然而,Go 确实存在未定义行为:如果你的程序存在数据竞争,那么行为就是未定义的。)

这就是 Go 语言安全神话中最大的裂痕。

在 Rust 中,编译器借用检查器(Borrow Checker)会在编译期阻止数据竞争,因此 Rust 可以自豪地宣称“无数据竞争”。但 Go 选择了更简单的并发模型,允许 Goroutine 共享内存。

一旦发生数据竞争(Data Race),即多个 Goroutine 同时访问同一块内存且至少有一个是写操作,Go 就不再提供任何保证。

为什么数据竞争是真正的 UB?

很多 Gopher 认为数据竞争只是“读到了旧数据”或者“计数器少加了 1”。这是一种极其危险的误解。在多核 CPU 和现代编译器优化的加持下,数据竞争在 Go 中可能导致内存安全破坏

这主要源于 Go 的多字数据结构(Multi-word Data Structures)

接口(Interface)的“撕裂”

Go 的 interface 在底层是由两个机器字组成的:{type_ptr, data_ptr}。

  • type_ptr 指向具体类型的元数据(如方法表)。
  • data_ptr 指向具体的数据值。

假设我们有一个全局接口变量 var i interface{},以及两个实现类型 type A 和 type B。

  • Goroutine 1 试图将 i 赋值为 A{}。
  • Goroutine 2 试图将 i 赋值为 B{}。

如果没有加锁,Goroutine 3 可能会读到一个“弗兰肯斯坦”般的怪物接口:它的 type_ptr 来自 A,但 data_ptr 却指向 B 的数据!

当你调用这个接口的方法时,程序会尝试用 A 的方法表去操作 B 的内存布局。这会导致什么?

如果运气好,你会得到Panic(类型断言失败或非法内存访问)。

反之,如果运气不好,那远程代码执行(RCE)的攻击者可以精心构造内存布局,利用这种类型混淆(Type Confusion)来劫持控制流。

切片(Slice)的“越界”

切片由 {ptr, len, cap} 三个字组成。数据竞争可能导致你读到了新的 len(变得很大),但 ptr 还是旧的(指向一个小数组)。结果是你拥有了一个长度远超底层数组容量的切片,这让你能够读取甚至修改不属于该切片的任意内存——这正是 C 语言缓冲区溢出的翻版。

这,就是 Go 中的 Undefined Behavior。 它不是“鼻恶魔”,但它是真实存在的安全黑洞。

那些“未指明”的灰色地带

除了致命的 UB,讨论中还涉及了 Go 语言规范中的另一种存在:未指明行为(Unspecified Behavior)实现定义行为(Implementation-Defined Behavior)

这些行为虽然不会导致内存破坏,但同样破坏了程序的“确定性”。

Map 的迭代顺序

在 Go 中,for k, v := range m 的顺序是故意未定义的。

Ian 解释说,这是为了防止开发者依赖某种特定的哈希实现顺序。Go 运行时甚至在每次迭代开始时引入了随机种子(迭代器会在map bucket 数组中随机选取一个起始位置向后遍历),强制让顺序变得不可预测。

这是一个非常有智慧的设计:通过强制随机化,逼迫开发者编写不依赖顺序的健壮代码。

表达式求值顺序:在“确定”与“未指明”之间

在 C/C++ 中,f(g(), h()) 中 g() 和 h() 谁先执行是未定义的(Undefined Behavior 或 Unspecified Behavior),这取决于编译器实现。

Go 语言规范对此做了更严格的规定,但依然保留了一块微妙的“灰色地带”。

确定的部分(Defined):

Go 规定,在求值表达式的操作数、赋值语句或返回语句时,所有的函数调用、方法调用和通信操作(Channel receive)都必须按照词法上从左到右的顺序执行。

例如,在赋值语句 y[f()], ok = g(h(), i()+x[j()], <-c), k() 中,函数调用和通信的发生顺序被严格锁定为:

f() -> h() -> i() -> j() -> <-c -> g() -> k()。

未指明的部分(Unspecified):

然而,规范同时也指出:并没有规定上述事件与表达式求值、索引操作、以及变量 y 的求值之间的顺序。

这意味着,虽然函数调用的相对顺序是固定的,但涉及副作用(Side Effects)的变量读写顺序可能是不确定的。来看 Spec 中的经典反例:

a := 1
f := func() int { a++; return a }

// x 可能是 [1, 2] 也可能是 [2, 2]
// 因为 a 的求值与 f() 的执行顺序未定义
x := []int{a, f()}
println(a, x)

// --- 示例:map 字面量中 key/value 的求值顺序未定义 ---
b := 1
g := func() int { b++; return b } // g() 会修改 b

// 若 b 先被求值:key=1, value=2  → m = {1: 2}
// 若 g() 先被执行:key=2, value=2 → m = {2: 2}
// Go 规范不保证 key 表达式与 value 表达式谁先求值
m2 := map[int]int{b: g()}
println(b, m2[b])

虽然 Go 比 C/C++ 确定得多,但在编写依赖于求值顺序的副作用代码(例如在参数列表中修改全局变量)时,依然可能会掉进“未指明行为”的陷阱。因此,最好不要在单行表达式中依赖复杂的副作用顺序。

浮点数转换的幽灵

讨论中有开发者 提到了 float64 转换为 uint8 的行为。在早期的 Go 版本中,对于溢出值的处理可能依赖于底层硬件指令(x86 vs ARM),从而表现出不一致。

虽然 Go 正在逐步收紧这些规范,例如 #76264 提案(尚未落地)正试图统一浮点转整数的饱和行为,但这提醒我们:即使是强类型语言,在跨平台移植时也可能遇到底层架构带来的“方言”差异。

如何在充满 UB 的世界里生存?

既然 Go 没有彻底消灭 UB,作为开发者,我们该如何自保?

视 -race 为生命线

Ian Lance Taylor 的警告应该被打印在每个 Go 开发者的工位上。

建议

  • 单元测试必须开启 -race 标志运行。
  • 在 CI/CD 流水线中,竞态检测是不可跳过的阻断性步骤。
  • 不要相信“我的并发逻辑很简单,不会出错”,人脑无法模拟现代 CPU 的乱序执行。

敬畏 unsafe

Go 的 unsafe 包是通往 C 语言 UB 世界的后门。使用 unsafe.Pointer 进行类型转换时,你实际上是在对编译器说:“我知道我在做什么,出了事我负责。”

除非你是编写底层运行时或极致性能库的专家,否则在业务代码中绝对禁止使用 unsafe。一旦使用,你必须熟读《Go 内存模型》和《垃圾回收器写屏障规则》。

理解“实现定义”与“未定义”的区别

  • 未定义(UB):可能导致 Crash、数据损坏、安全漏洞(如数据竞争)。零容忍。
  • 未指明/实现定义:不同版本或平台可能表现不同(如 Map 顺序)。不要依赖它。
  • 已定义:Go 承诺的行为(如整数回绕)。可以依赖,但需知晓代价。

小结:完美的幻象与工程的现实

通过这次“真相调查”,我们得出的结论可能有些令人沮丧,但也足够清醒:

Go 语言并没有彻底消灭 Undefined Behavior。它只是通过牺牲一部分性能和增加运行时检查,将 UB 的“攻击范围”从 C/C++ 的“随处可见”缩小到了“并发数据竞争”和“不安全代码”这两个特定的领域。

这是一种极其成功的工程权衡。它让 Go 在保持高性能的同时,为 99% 的日常编码提供了坚实的安全保障。

然而,作为 Gopher,我们不能沉浸在“绝对安全”的幻象中。我们必须意识到,当我们敲下 go func() 的那一刻,当我们试图共享一个指针的那一刻,我们正行走在悬崖的边缘。

Go 给了我们围栏(定义明确的行为),但也给了我们梯子(并发与 Unsafe)。能否不跌入 UB 的深渊,最终取决于我们是否遵守工程的纪律。

资料链接:https://groups.google.com/g/golang-nuts/c/MB1QmhDd_Rk


你遇到过“鼻恶魔”吗?

哪怕是 Go 这样严谨的语言,在并发面前也会露出锋利的牙齿。在你的开发生涯中,是否遇到过那种因为没开 -race 而在生产环境产生的“灵异事件”?你对 Go 这种“用性能换确定性”的哲学怎么看?

欢迎在评论区分享你的“探案”心得!


还在为“复制粘贴喂AI”而烦恼?我的新专栏 AI原生开发工作流实战 将带你:

  • 告别低效,重塑开发范式
  • 驾驭AI Agent(Claude Code),实现工作流自动化
  • 从“AI使用者”进化为规范驱动开发的“工作流指挥家”

扫描下方二维码,开启你的AI原生开发之旅。


你的Go技能,是否也卡在了“熟练”到“精通”的瓶颈期?

  • 想写出更地道、更健壮的Go代码,却总在细节上踩坑?
  • 渴望提升软件设计能力,驾驭复杂Go项目却缺乏章法?
  • 想打造生产级的Go服务,却在工程化实践中屡屡受挫?

继《Go语言第一课》后,我的《Go语言进阶课》终于在极客时间与大家见面了!

我的全新极客时间专栏 《Tony Bai·Go语言进阶课》就是为这样的你量身打造!30+讲硬核内容,带你夯实语法认知,提升设计思维,锻造工程实践能力,更有实战项目串讲。

目标只有一个:助你完成从“Go熟练工”到“Go专家”的蜕变! 现在就加入,让你的Go技能再上一个新台阶!


商务合作方式:撰稿、出书、培训、在线课程、合伙创业、咨询、广告合作。如有需求,请扫描下方公众号二维码,与我私信联系。

© 2026, bigwhite. 版权所有.

🔲 ☆

Rust 的“跨越鸿沟”时刻:Ubuntu 全面拥抱 Rust 意味着什么?

本文永久链接 – https://tonybai.com/2026/02/25/rust-crossing-the-chasm-ubuntu-embrace

大家好,我是Tony Bai。

在技术世界里,一门编程语言的成功往往分为两个阶段:第一阶段是赢得“极客”和“先驱者”的狂热追捧;第二阶段则是说服那些保守、务实的“早期大众”将其投入到枯燥却庞大的企业级生产中。这两个阶段之间,横亘着一条深不见底的“鸿沟”。

2026 年初,Rust 核心团队成员、语言设计的灵魂人物 Niko Matsakis 在参加完 Rust Nation 大会后,发表了一篇引人深思的文章——《What it means that Ubuntu is using Rust》。在这篇随笔中,Niko 借由 Canonical(Ubuntu 的母公司)全面拥抱 Rust 这一标志性事件,极其坦诚地剖析了 Rust 当前在行业接纳生命周期中所处的位置、面临的阵痛,以及为了走向真正的“工业标准”,Rust 社区必须在技术和心理上做出的巨大改变。

本文将深度解读 Niko 的这篇文章,带你透视 Rust 在“后狂热时代”的商业化演进路线、标准库之争、开源商业模式,以及为何“同理心”成了这门硬核语言最大的护城河。

无处不在的“鸿沟”——Rust 到底走到哪了?

如果你熟悉硅谷营销大师杰弗里·摩尔(Geoffrey Moore)的经典理论《跨越鸿沟》(Crossing the Chasm),就会知道任何一项高科技产品在市场推广时,都会经历创新者(Innovators)、早期采用者(Early Adopters)、早期大众(Early Majority)、后期大众(Late Majority)和落后者(Laggards)五个阶段。而在“早期采用者”与“早期大众”之间,存在着一个巨大的断层,这就是“鸿沟”。

Rust 跨过这条鸿沟了吗?

Niko 给出的答案是:这取决于你问的是谁。

  • 在某些互联网巨头(大厂)中:答案是“已经跨越了一大半”。比如在亚马逊云(AWS)这样对性能和资源有着极致苛求的地方,Rust 已经被牢牢确立为构建大规模数据平面(Data Planes)和资源感知代理(Agents)的“正确选择”。它甚至正在向设备端和机器人领域的底层代码渗透。
  • 在普通企业应用中:依然存在一种根深蒂固的刻板印象——“Rust 是给 S3(亚马逊云存储)那些穿西装打领带的高级工程师用的,对于我们普通的 CRUD(增删改查)业务来说,完全是杀鸡用牛刀。”
  • 在安全关键软件(Safety Critical Software)领域:比如汽车的转向柱控制系统或航空航天系统,Rust 依然在艰难地寻找立足点。大多数传统工业巨头仍处于“观望”状态,他们希望让早期采用者先去铺路、踩坑。

这揭示了一个残酷的现实:技术上的优越性并不等同于市场上的普遍接受度

当技术走向“早期大众”时,受众的心态发生了根本性变化。

早期采用者买的是“变革”,他们愿意容忍不成熟的生态,只为获得降维打击的竞争优势;而“早期大众”买的是“生产力提升”,他们极度厌恶风险,追求的是业务连续性——他们想要的是进化,而不是革命。

寻找“标杆客户”——Ubuntu 搭建的跨越之桥

如何说服那些极度厌恶风险的“早期大众”尝试新事物?唯一的答案是:让他们看到与他们相似的成功案例。

这就是为什么 Canonical(Ubuntu 背后的公司)的入局对 Rust 生态具有决定性的历史意义。在 Rust Nation 大会上,Canonical 的工程副总裁 Jon Seager 发表了题为《在 Ubuntu 中大规模采用 Rust》的闭幕演讲。这场演讲完美诠释了什么是“既有远见,又极其务实”。

Canonical 明确表示,他们已将公司内部开发的语言收敛为一个极小的集合:Python、C/C++ 和 Go。

而现在,Rust 被正式引入,并被确立为编写新底层基础工具的首选语言,逐步取代 C、C++ 以及部分 Python 的使用场景。

更令人振奋的是,Canonical 不仅仅是自己“用”,他们还在“反哺”生态,充当桥梁。

Jon Seager 谈到了 Ubuntu 作为操作系统发行版的责任——通过支持内存安全的基础设施库来“向前支付(Pay it forward)”。Canonical 正在提供财务和声誉上的双重支持:
1. 赞助 Trifecta Tech 基金会开发 sudo-rs 和 ntpd-rs(用 Rust 重写关键的系统组件)。
2. 赞助 uutils 组织开发 Rust 版的 coreutils(Linux 核心命令集)。

为什么说 Ubuntu 是完美的“标杆客户”?

在 Linux 用户态领域,Ubuntu 的体量和权威性毋庸置疑。当 Ubuntu 愿意承担尝试新事物的风险,并证明“用 Rust 重写 sudo 是可行的且更安全的”时,这种示范效应是巨大的。

那些“早期大众”企业看到这一幕时会想:“如果连 Ubuntu 这样对稳定性要求极其变态的操作系统底层都在用 Rust,那我们的业务系统用 Rust 应该也是安全的。”

这正是《跨越鸿沟》中破局的核心策略:利用标杆客户的背书,提供能无缝融入现有工作流的“即插即用”方案,从而最小化系统的不连续性。

成长的阵痛——为了壮大,Rust 必须改变“人设”

当目标受众从追求极致的“极客”变成追求稳定的“务实派”时,Rust 面临着一种极其尴尬的转型痛点。

Niko 在文中引用了《跨越鸿沟》里的一段话:

“在任何两个采用群体之间的过渡通常都是极度令人尴尬的,因为你必须在你对旧策略感到最舒服的时候采用新策略……当务实派想听到‘行业标准(Industry Standard)’时,科技公司可能还在向他们推销‘最先进的技术(State-of-the-art)’。”

这精准地命中了 Rust 当下的软肋。

在过去的十年里,Rust 社区的营销口号是“零成本抽象”、“无畏并发”、“最先进的内存安全所有权模型”。这套说辞成功吸引了早期的系统工程师。

但如今,当 Rust 走向大众时,普通开发者更关心的是:“有没有现成的库?”、“编译能不能快点?”和“能不能开箱即用?”

核心冲突爆发点:标准库的规模之争。

在闭门晚宴上,Canonical 的 Jon Seager 提出了一个极具挑衅性的观点:Rust 需要重新审视其维持“极小标准库(Small Standard Library)”的政策。

长期以来,Rust 奉行“标准库只包含最核心的类型和原语,其余全部交给社区(Crates.io)”的哲学。比如,Rust 的标准库里甚至没有随机数生成、正则表达式或 HTTP 客户端。这种设计在早期非常受极客欢迎,因为它保证了核心库的轻量级,并允许社区自由竞争出最好的第三方库(如 serde、tokio)。

但对于“早期大众”来说,这简直是个噩梦。他们不明白为什么解析一个 JSON 或发起一个 HTTP 请求都需要在数以万计的第三方包中去筛选、评估安全性、担心供应链投毒。他们想要的是像 Go 语言或 Python 那样“内置电池(Batteries Included)”的开箱即用体验。

实际上,Rust 社区在 2016 年曾推出过一个名为“Rust 平台(Rust Platform)”的提案,试图官方“钦定”一批高质量的第三方包作为“扩展标准库”。但当时遭到了早期采用者的强烈抵制,理由是“直接改 Cargo.toml 很容易,没必要官方下场干预”。

Niko 反思道:当年早期采用者讨厌的东西,恰恰可能是如今“早期大众”最渴望的东西。

Rust 必须面对现实:过去引导其成功的信条,正在阻碍其向更广阔的市场迈进。

Niko 透露,他正在构思一个名为“电池包(Battery packs)”的新项目,试图在不搞庞大标准库的前提下,为企业级用户提供一种官方背书的、开箱即用的库集合方案。这标志着 Rust 正在从“追求它能成为什么样(What it could be)”向“承认它实际是什么样(What it actually is)”的务实转变。

商业与开源的闭环——如何将“采用率”转化为“真金白银”?

任何一门编程语言生态的长远发展,都离不开雄厚的资金支持。随着 Rust 采用率的爆炸式增长,对 Rust 开源项目和生态系统的维护压力也与日俱增。钱从哪来?

Niko 分享了几个关于开源投资的深刻洞见,这不仅适用于 Rust,对所有开源项目(包括 Go、Node.js 生态)都有极大的启发。

洞见一:投资不一定只是“砸钱”,更是“下场共建”。

对于像 Canonical 这样的纯粹开源组织,最宝贵的投资是“建立深度的组织间关系”。

在“Rust for Linux”项目中,早期都是 Rust 核心维护者在帮 Linux 内核开发者修 Bug。但随着时间推移,现在越来越多的 Linux 内核开发者开始自己动手修复 Rust 编译器或工具链的问题,而 Rust 维护者则退居幕后扮演导师的角色。这种“授人以渔”的贡献,比单纯的捐款更有价值。

洞见二:钱往往在公司“采用 Rust 之前”到来,而不是之后。

我们通常认为,企业是在大量使用某个开源软件后,出于反哺或维护自身利益的目的才会掏钱赞助。

但 Niko 观察到了一个完全不同的趋势:更容易获取的资金,来自于那些“正在考虑但尚未采用” Rust 的公司。

在这些公司内部,通常有一批“早期采用者”(内推者),他们试图说服保守的公司管理层采用 Rust。为了促成此事,他们往往需要拿着一份“准入条件清单”——比如,Rust 必须支持某种特定的芯片架构,或者必须具备某个安全认证组件。

更关键的是,这些内推者手里往往握有预算。为了让这门技术顺利落地公司,他们愿意花钱去填补 Rust 生态中的这些空白。

Rust 基金会的 Alexandru Radovici 证实了这一点:许多对安全性要求极高的公司,手里攥着钱想帮 Rust 补齐短板,却“不知道该怎么花这笔钱”。Canonical 赞助 sudo-rs 本质上也是一样的——他们是在花钱扫除阻碍 Ubuntu 更大规模采用 Rust 的障碍。

开源社区需要建立一种机制,精准对接这些带着预算的“潜在采用者”,将他们的痛点转化为开源项目的开发资金。

社区的终极考验——同理心是最大的护城河

在文章的最后,Niko 抛出了一个直击灵魂的观点,这不仅是给 Rust 社区的警钟,也是所有程序员的必修课:

“如果我们在其中表现得太像‘中学生(Middle School)’,那开源跨越鸿沟的愿景就会彻底破灭。”

什么是“中学生”行为?

当你深度参与一个开源社区时,你会觉得这里充满阳光,欢迎所有人。但对于外部的“早期大众”来说,开源社区往往看起来像一个充满小圈子、潜规则和“口口相传的规矩(Oral traditions)”的排外组织。

一个企业级的保守开发者,带着一个务实的业务问题来到社区提问。他可能只是用错了一个术语,或者没有遵循某种隐形的“社区政治正确”,结果就遭到了一群激进贡献者的群嘲、冷嘲热讽,甚至因为提出不同的设计理念而被强硬关闭 Issue。

这位企业开发者根本分不清哪些是喷子,哪些代表官方立场。他只会觉得:“这个语言的社区太有毒了,我们公司还是用 Java 吧。”

只需要一次粗鲁的回复,就能彻底赶走一个潜在的企业级标杆客户。

Niko 强调,帮助 Rust 最终取得成功的,绝不是更快的编译速度或更完美的类型系统,而是“开源中的同理心”。

“早期大众”并不想参与编程语言的“宗教战争”,他们不关心“纯粹性”,他们只是想按时下班,安全地把产品发布出去。Rust 社区必须学会倾听这群人的声音,理解他们的价值观,用温和、包容和同理心去服务他们,而不是用技术傲慢去居高临下地教训他们。

小结:语言的进化,更是心智的成熟

从 2015 年发布 1.0 版本至今,Rust 用了十余年的时间,证明了自己在技术和理论上的卓越。如今,借由 Ubuntu 这样的重磅标杆客户的背书,它正式站在了跨越主流企业级市场鸿沟的跳板上。

Niko Matsakis 的这篇文章,不仅是对 Rust 现状的一份清醒诊断,更是对整个技术生态演进规律的深刻洞察,也非常值得其他主流编程语言的掌舵者和社区学习借鉴。

无论是标准库的扩展、商业投资机制的完善,还是社区同理心的建设,都表明 Rust 正在经历一场脱胎换骨的“成年礼”。它正在从一个由极客驱动的“炫酷玩具”,蜕变为一个能够承载人类核心数字基础设施的“工业巨兽”。

也许属于 Rust 的激荡时代,才刚刚开始。

资料链接:https://smallcultfollowing.com/babysteps/blog/2026/02/23/ubuntu-rustnation/


你认为 Rust 该“扩充”标准库吗?

Rust 坚持“极小标准库”让极客疯狂,却让企业用户头大。你是支持 Go 这种“内置电池”的开箱即用,还是支持 Rust 这种“社区竞争”的极简主义?你在项目中是否也曾因为 Rust 缺乏某个基础库(如随机数、正则)而感到沮丧?

欢迎在评论区分享你的看法!


还在为“复制粘贴喂AI”而烦恼?我的新专栏 AI原生开发工作流实战 将带你:

  • 告别低效,重塑开发范式
  • 驾驭AI Agent(Claude Code),实现工作流自动化
  • 从“AI使用者”进化为规范驱动开发的“工作流指挥家”

扫描下方二维码,开启你的AI原生开发之旅。


你的Go技能,是否也卡在了“熟练”到“精通”的瓶颈期?

  • 想写出更地道、更健壮的Go代码,却总在细节上踩坑?
  • 渴望提升软件设计能力,驾驭复杂Go项目却缺乏章法?
  • 想打造生产级的Go服务,却在工程化实践中屡屡受挫?

继《Go语言第一课》后,我的《Go语言进阶课》终于在极客时间与大家见面了!

我的全新极客时间专栏 《Tony Bai·Go语言进阶课》就是为这样的你量身打造!30+讲硬核内容,带你夯实语法认知,提升设计思维,锻造工程实践能力,更有实战项目串讲。

目标只有一个:助你完成从“Go熟练工”到“Go专家”的蜕变! 现在就加入,让你的Go技能再上一个新台阶!


商务合作方式:撰稿、出书、培训、在线课程、合伙创业、咨询、广告合作。如有需求,请扫描下方公众号二维码,与我私信联系。

© 2026, bigwhite. 版权所有.

🔲 ☆

当“安全性”遭遇“交付速度”:2026 年,我为什么告别了 Rust

本文永久链接 – https://tonybai.com/2026/02/21/safety-vs-delivery-speed-why-farewell-rust-in-2026

大家好,我是Tony Bai。

在软件工程的铁三角中,Rust 占据了“安全性”与“性能”的绝对高地。凭借借用检查器(Borrow Checker)和极其严格的类型系统,它向开发者承诺了一个没有内存错误、没有空指针崩溃的完美世界。

然而,在商业软件开发的战场上,还有一个至关重要的维度往往被技术纯粹主义者忽视,那就是——交付速度(Delivery Speed)

近日,资深工程师 Dmitry Kudryavtsev 发表了长文《Farewell, Rust》,详述了他为何忍痛将一个运行了多年、已盈利的 Rust 项目全盘重写为 Node.js 的心路历程。这篇文章也引发了一场关于“为了极致的安全性,我们是否值得牺牲过多的交付速度?”的深刻辩论。

缘起:一个 C/C++ 老兵的“安全梦”

Dmitry 绝非那些被即时编译(JIT)宠坏的脚本小子。相反,他的技术底色是硬核的 C/C++。

早在高中时代,他就沉迷于指针的魔力,痴迷于手动管理内存的掌控感。他写过 3D 渲染器、IRC 机器人,甚至操作系统内核。然而,由于第一份工作是 PHP Web 开发,他被迫进入了动态语言的世界。虽然 PHP、Python 和 Ruby 带来了 Web 开发的极速体验,但在内心深处,他始终怀念 C 语言那种“压榨硬件每一滴性能”的快感,同时也痛恨 C 语言中防不胜防的内存安全漏洞。

直到 Rust 横空出世。

对于像 Dmitry 这样的工程师来说,Rust 简直就是“鱼与熊掌兼得”的梦想:

  • 低级控制力:像 C 一样精确控制内存布局。
  • 安全性:编译器在编译阶段就能消除一整类内存错误。
  • 现代体验:拥有像 Cargo 这样优秀的包管理工具。

于是,他做了一个所有热血工程师都会做的决定:为了追求极致的质量与安全,用 Rust 从零构建一个商业 Web 应用。

起初,一切都很完美。他在 2023 年底成功上线了项目,甚至因此受邀在两个技术大会上发表演讲。但随着时间的推移,业务逻辑日益复杂,“安全性”的红利开始被“交付速度”的损耗所抵消。到了 2026 年初,为了项目的生存,他不得不做出了那个艰难的决定:告别 Rust

深度复盘:Rust 在 Web 交付中的“五大减速带”

Dmitry 的文章之所以珍贵,是因为他用亲身经历证明了:在 Web 开发的特定场景下,Rust 引以为傲的“安全性”机制,如何一步步变成了拖慢“交付速度”的罪魁祸首。

1. 模板与视图:类型安全 vs. 迭代速度

在后端逻辑中,Rust 的类型系统坚不可摧。但当数据流向前端(HTML/Email 模板)时,这种为了安全而设计的严格性,变成了修改 UI 时的噩梦。

  • 安全性的代价:为了保证编译时的类型安全,Rust 社区诞生了 Maud 或 Askama 这样的编译时模板库。它们通过宏(Macro)在编译期检查 HTML 模板中的每一个变量引用。这听起来很棒,意味着你永远不会渲染出错误的变量。
  • 速度的牺牲:但这带来的副作用是,每次修改 HTML 哪怕一个标点符号,都会触发漫长的重新编译。在 Web 前端开发这种需要“所见即所得”的高频迭代场景下,这种等待是毁灭性的。
  • 对比 Node.js:TypeScript 配合 JSX/TSX 提供了全链路的类型安全,同时保持了极快的热重载(Hot Reload)速度。重构一个字段,VS Code 会立即标红所有受影响的视图组件,修改后毫秒级生效。这种“安全且快”的体验,是 Rust 目前无法提供的。

2. 国际化(i18n):生态缺失带来的效率黑洞

对于商业应用,支持多语言是刚需。

虽然 Mozilla 开发了 Project Fluent,但 Rust 生态中缺乏成熟的、开箱即用的 i18n 解决方案。你往往需要为了“正确性”而去处理繁琐的加载逻辑和类型绑定,编写大量的胶水代码。而Node.js生态中的i18next 等库不仅极其成熟,还能配合 TypeScript 提供键值级别的类型安全。Node.js 原生内置了完整的 ICU 标准(Intl API),处理货币、日期、复数格式化信手拈来。在这一点上,Rust 开发者需要花费数倍的时间来实现同样的功能,严重拖慢了产品推向全球市场的速度。

3. “动态”业务 vs. “静态”约束

Web 业务充满了动态性:用户提交的 JSON 结构可能是不确定的,筛选条件的组合可能是无穷的。Rust 试图用静态类型系统去约束这些动态行为,结果就是开发效率的暴跌。

  • 序列化之痛:serde 是 Rust 的瑰宝,但在处理复杂的、充满 Option 的业务数据时,为了安全地取出一个嵌套字段,你不得不编写大量的 match 或 unwrap 处理代码。为了优雅地处理错误,Dmitry 定义了十几个自定义错误枚举。虽然代码很健壮,但写起来太慢了。
  • SQL 的僵局:sqlx 提供了极其强大的编译时 SQL 检查,这在静态查询时非常棒。但是,一旦你需要根据用户输入动态构建查询(例如:用户选了 A 筛选条件就加个 WHERE 子句),Rust 的强类型系统就变成了噩梦。你无法像在 Node.js 中使用 Kysely 或 Prisma 那样,流畅地拼接查询片段。为了“安全”地构建 SQL,你付出了巨大的代码复杂度成本。

4. 编译时间:CI/CD 的隐形杀手

这是最让 Dmitry 崩溃的一点,也是“交付速度”最直观的体现。

  • Rust 的等待:随着依赖增多(尤其是使用了大量宏的 Web 框架),编译时间呈指数级增长。Dmitry 的 CI 流程需要 12-14 分钟 才能完成部署。“每次我在 Sentry 上看到一个简单的 Bug,想到修复它需要等待 15 分钟的构建流程,我就失去了修复的动力。”
  • Node.js 的极速:迁移到Node.js后,完整的 CI 流程(含 Lint 和测试)仅需 5 分钟。部署速度提升了 3 倍。这意味着“发现 Bug -> 修复 -> 上线”的反馈闭环被大大缩短了。在商业竞争中,修复速度往往比绝对的“无 Bug”更重要。

5. 生态成熟度:造轮子的时间成本

Rust 的 Web 生态虽然在成长,但面对长尾需求时仍显稚嫩。

  • 场景:你需要集成一个冷门的第三方支付网关,或者处理一个特定的 Webhook 签名验证。
  • Rust 的困境:官方 SDK?没有。社区库?两年前就不更新了。为了安全,你不得不对着 API 文档,自己手写 HTTP 请求、自己实现加密验签逻辑。这占用了大量本该用于开发业务核心功能的时间。
  • Node.js 的便利:npm install 通常能解决一切。几乎所有 SaaS 服务商都会提供第一方的 Node.js SDK。“拿来主义”是提升交付速度的最佳捷径。

总结与反思:我们到底为了什么而编程?

Dmitry 的文章并没有否定 Rust 的价值。相反,他依然热爱 Rust,依然怀念那些与编译器“斗智斗勇”并最终获得完美代码的日子。

他的结论非常客观,为所有正在做技术选型的团队提供了一把衡量“安全”与“速度”的标尺:

  1. 资源占用 vs. 开发效率的账本
    Rust 版本的应用内存占用仅 60-80MB,而 Node.js 版本约为 117MB。
    Rust 确实更省资源。但对于业务应用来说,这 50MB 的内存差异,在云服务器几美元一个月的成本面前不值一提。然而,为了节省这 50MB 内存,开发者付出了几倍的开发时间、调试精力以及心智负担。这笔账,在商业逻辑上是划不来的。

  2. 技术选型的“黄金法则”

    • 何时拥抱“安全性”(选 Rust):如果你在构建数据库内核、搜索引擎、高频交易系统、嵌入式设备固件,或者像 Lambda 这样对冷启动时间极度敏感的 Serverless 函数。在这些场景下,性能和稳定性是核心竞争力,为了安全牺牲开发速度是值得的。
    • 何时拥抱“交付速度”(选 Node.js/Go/Python):如果你在构建 CRUD 后端、SaaS 业务逻辑、内部管理工具,或者处于需要快速试错、频繁变更需求的初创阶段。在这些场景下,迭代速度(Velocity)才是核心竞争力。
  3. 给 Go 开发者的启示
    有趣的是,Dmitry 在注脚中提到了 Go:“Yes, there is Go. But I never really had the chance to like Go.”
    这其实是一个非常有意思的信号。在 Rust 的“极致安全”和 Node.js 的“极致速度”之间,Go 恰恰占据了那个“黄金平衡点”

    • 它有静态编译和类型系统,比 Node.js 更安全、性能更好。
    • 它有极快的编译速度和简单的语法,比 Rust 的心智负担低得多。
    • 它有极其成熟的中间件和微服务生态。

    对于那些厌倦了 Node.js 运行时错误,又被 Rust 借用检查器拖慢脚步的 Web 开发者来说,Go 依然是当下最务实的选择。

小结

技术选型从来没有绝对的优劣,只有“最适合当下约束条件的工具”。

Dmitry 的故事提醒我们:不要因为手里拿着“安全性”这把锤子(Rust),就无视了“交付速度”这个钉子。在商业软件的世界里,有时候,为了让产品活下去,为了让用户更快用上新功能,“足够好”且“跑得快”的代码,往往比“完美但迟到”的代码更有价值。

Rust 是系统编程的未来,但这并不意味着它是所有 Web 业务的终点。对于独立开发者或初创团队而言,“快”,本身就是一种极其重要的功能。

资料链接:https://yieldcode.blog/post/farewell-rust/


你会为了“安全”放弃“速度”吗?

软件工程永远是权衡的艺术。在你的项目中,你是否也曾为了追求某种“先进特性”,而导致项目进度失控?如果给你 50MB 的内存节省,你愿意多等 10 分钟的编译时间吗?

欢迎在评论区分享你的选型纠结!


还在为“复制粘贴喂AI”而烦恼?我的新专栏 AI原生开发工作流实战 将带你:

  • 告别低效,重塑开发范式
  • 驾驭AI Agent(Claude Code),实现工作流自动化
  • 从“AI使用者”进化为规范驱动开发的“工作流指挥家”

扫描下方二维码,开启你的AI原生开发之旅。


你的Go技能,是否也卡在了“熟练”到“精通”的瓶颈期?

  • 想写出更地道、更健壮的Go代码,却总在细节上踩坑?
  • 渴望提升软件设计能力,驾驭复杂Go项目却缺乏章法?
  • 想打造生产级的Go服务,却在工程化实践中屡屡受挫?

继《Go语言第一课》后,我的《Go语言进阶课》终于在极客时间与大家见面了!

我的全新极客时间专栏 《Tony Bai·Go语言进阶课》就是为这样的你量身打造!30+讲硬核内容,带你夯实语法认知,提升设计思维,锻造工程实践能力,更有实战项目串讲。

目标只有一个:助你完成从“Go熟练工”到“Go专家”的蜕变! 现在就加入,让你的Go技能再上一个新台阶!


商务合作方式:撰稿、出书、培训、在线课程、合伙创业、咨询、广告合作。如有需求,请扫描下方公众号二维码,与我私信联系。

© 2026, bigwhite. 版权所有.

🔲 ☆

Go, Rust 还是 Zig?一场关于“简单”与“控制”的灵魂拷问

本文永久链接 – https://tonybai.com/2026/01/17/go-rust-zig-simplicity-vs-control

大家好,我是Tony Bai。

在系统编程的世界里,开发者似乎总是面临着一个残酷的二选一:是选择极致的简单与生产力,还是选择绝对的控制与零成本抽象

这种纠结在 Go 与 Rust 的长期对峙中体现得淋漓尽致。然而,近日一位拥有十年 Go 经验的资深开发者在Zig社区的分享,似乎为这场二元对立的战争撕开了一道口子。他从 Go 迁移到 Zig 的经历,既是一个技术选型的故事,也是一场关于“我们到底需要什么样的编程语言”的深度辩论。

Go 的困境:当“简单”成为一种束缚

对于许多 Gopher 来说,Go 的简单是其最大的武器,但也是最深的痛点。

这位楼主坦言,尽管他深爱 Go 的简单,但在编写某些复杂系统时,这种“过度简化”让他感觉语言本身存在缺陷。

  • 表达力的缺失:Go 缺乏像 Rust 那样的 Enum (带数据的枚举)、Option 和 Result 类型。在处理复杂状态和错误流时,Go 的代码往往显得啰嗦且缺乏约束力。
  • “差不多”的无奈:为了保持简单,Go 在很多地方做了折中(比如 GC,比如泛型的实现方式)。当你需要榨干硬件性能或追求极致的内存布局时,Go 显得力不从心。

Rust 的围城:控制的代价是复杂度

如果嫌 Go 太简单,Rust 似乎是理所当然的替代者。但对于很多习惯了 Go “写完即运行”体验的开发者来说,Rust 的门槛是一堵高墙。

楼主表示,他喜欢 Rust 的核心概念(Structs, Enums, Option),但 Rust 为了内存安全而引入的借用检查器、生命周期以及复杂的异步模型,让他感觉“像是面对另一个 C++”。

这是一场灵魂拷问:为了获得控制权,我们真的需要背负如此沉重的认知包袱吗?

Zig 的破局:在“简单”与“控制”之间走钢丝

Zig 的出现,似乎精准地击中了 Go 与 Rust 之间的那个真空地带。对于这位 Gopher 来说,Zig 让他感到了久违的“刚刚好”:

  1. 显式的哲学(像 Go):Zig 没有隐式内存分配,没有隐藏的控制流,也没有预处理器。这种“所见即所得”的代码风格,与 Go 的可读性哲学高度共鸣。
  2. 现代的类型系统(像 Rust):Zig 提供了 comptime(编译期执行)和丰富的类型系统,弥补了 Go 在表达力上的短板,却又没有引入 Rust 那样复杂的生命周期概念。
  3. 对 C 的降维打击:Zig 不仅是一门语言,更是一个强大的 C/C++ 构建工具链。它允许你无缝地与 C 交互,逐步迁移遗留代码,这是 Go (CGO) 和 Rust 都难以做到的顺滑体验。

社区的冷思考:没有免费的午餐

当然,这场灵魂拷问没有标准答案。社区的讨论也极其理性地指出了选择 Zig 的代价:

  • 生态的荒原:与 Go 庞大的“标准库+第三方库”相比,Zig 的生态仍处于拓荒期。你可能需要自己造很多轮子。
  • 内存管理的回归:Zig 没有 GC,也没有 Rust 的所有权模型。这意味着你回到了手动管理内存的时代(尽管有 defer 和 arena 等工具辅助)。对于习惯了 GC 的 Gopher 来说,这是一个必须跨越的心理门槛。
  • 稳定性的豪赌:Zig 尚未发布 1.0,语言特性仍在变动。选择 Zig,意味着你愿意陪它一起成长,也愿意承担变动的风险。

小结:你的灵魂属于哪里?

这场讨论最终指向了开发者内心的自我定位:

  • 如果你追求高效交付、团队协作和工业级的稳定性,Go 依然是不可撼动的王者。
  • 如果你追求数学般的严谨、绝对的安全和零成本抽象,且不介意陡峭的学习曲线,Rust 是你的圣杯。
  • 而如果你渴望掌控底层、厌倦了复杂的抽象、却又想要现代化的开发体验,Zig 也许就是你一直在寻找的那个“刚刚好”。

简单还是控制?这不仅是语言的选择,更是你作为工程师,想要如何与机器对话的选择。

资料链接:https://www.reddit.com/r/Zig/comments/1q38e50/im_really_surprised_by_how_simple_it_is_to/


你的“灵魂选择”

在“简单”与“控制”的天平上,你的心偏向哪一边?如果让你现在开始一个新项目,你会毫不犹豫地选择 Go,还是想尝尝 Zig 的鲜,亦或是死磕 Rust?

欢迎在评论区投出你的一票,并分享你的理由! 让我们看看谁才是开发者心中的“白月光”。

如果这篇文章引发了你的选型思考,别忘了点个【赞】和【在看】,并转发给那个还在纠结学什么语言的朋友!


还在为“复制粘贴喂AI”而烦恼?我的新专栏 AI原生开发工作流实战 将带你:

  • 告别低效,重塑开发范式
  • 驾驭AI Agent(Claude Code),实现工作流自动化
  • 从“AI使用者”进化为规范驱动开发的“工作流指挥家”

扫描下方二维码,开启你的AI原生开发之旅。


你的Go技能,是否也卡在了“熟练”到“精通”的瓶颈期?

  • 想写出更地道、更健壮的Go代码,却总在细节上踩坑?
  • 渴望提升软件设计能力,驾驭复杂Go项目却缺乏章法?
  • 想打造生产级的Go服务,却在工程化实践中屡屡受挫?

继《Go语言第一课》后,我的《Go语言进阶课》终于在极客时间与大家见面了!

我的全新极客时间专栏 《Tony Bai·Go语言进阶课》就是为这样的你量身打造!30+讲硬核内容,带你夯实语法认知,提升设计思维,锻造工程实践能力,更有实战项目串讲。

目标只有一个:助你完成从“Go熟练工”到“Go专家”的蜕变! 现在就加入,让你的Go技能再上一个新台阶!


商务合作方式:撰稿、出书、培训、在线课程、合伙创业、咨询、广告合作。如有需求,请扫描下方公众号二维码,与我私信联系。

© 2026, bigwhite. 版权所有.

❌