标签 RobPike 下的文章

哲学家与工程师:为何 Rust 和 Go 的“官方之声”如此不同?

本文永久链接 – https://tonybai.com/2025/08/21/go-rust-official-voices

大家好,我是Tony Bai。

最近,在阅读 Rust 核心团队负责人 Niko Matsakis 庆祝十周年的系列博文时,我注意到了一个有趣的现象。我下意识地将他的文字,与我长期关注的 Go语言之父Rob Pike以及Go 团队前技术负责人 Russ Cox 的文章放在一起对比。

这时我发现,两者窗外的风景截然不同。

一边,Niko Matsakis 这样写道:

“Graydon(Rust创始人)为我们设定了正确的‘北极星’……‘是的,我们可以拥有好东西’,我常这么想。这句话也捕捉到了 Rust 的另一种特质,那就是试图挑战关于‘权衡’的传统智慧。”

另一边,Russ Cox 在一篇关于 Go 模块依赖的重要文章中,开篇即是:

“本文定义了 Go 模块,这是对 go get 命令支持的版本化依赖的提议。这篇文章是七篇文章中的第一篇,描述了一个关于版本化 Go 的全面提案。”

可以看到,一种声音像一位哲学家,在讨论愿景和原则;另一种,则像一位总工程师,直接给出工程计划。

这并非偶然的文笔差异。

一门编程语言核心团队的写作风格,不只是表面的文字选择,而是其设计哲学、治理模式和社区文化的直接反映。 它在很大程度上预示了这门语言的演进方向,以及它最终会吸引哪一类开发者。

今天,我想和你一起分析这两种迥异的“官方之声”,并尝试回答一个核心问题:

在 Rust 的哲学思辨与 Go 的工程决断之间,究竟隐藏着怎样的语言灵魂与未来?

Rust 的“探索式叙事”——在复杂世界中寻求赋能

如果你长期阅读 Rust 官方博客或 Niko Matsakis 的个人博客,会发现一种独特的叙事模式:愿景驱动,讨论权衡,社区对话。

Niko 的“Rust 2025”系列,开篇并非罗列要实现的功能,而是先定义 Rust 的“核心使命”——赋能基础软件。他花了不少篇幅来构建一个叙事框架,用“北极星”来比喻指引方向的技术与文化原则,用“大力水手菠菜”来形容类型系统的作用,用“平滑的迭代式深化”来描述理想的用户体验。

这种风格的背后,是对一个根本事实的承认:系统编程本身是复杂的。

Rust 的设计哲学,不是回避这种复杂性,而是正视它,并提供一套强大的工具去驾驭它。这套工具,就是其所有权系统、生命周期和 Trait 系统。

这些工具无疑是复杂的,也带来了陡峭的学习曲线。但 Rust 官方文章的字里行间,总是在传达一个核心信念:这种复杂性,是为了换取一种前所未有的“赋能 (Empowerment)”。

当你掌握了这些工具,你便能在编译器的帮助下,编写出兼具高性能、内存安全和高度抽象的代码。这是一种“先难后易”的设计。Rust 的文章,就像一位向导,它不否认前路复杂,但会耐心解释工具的用法,并清晰地展示目标达成后所能获得的能力,让你相信这种投入是值得的。

这种“探索感”也体现在 Rust 的社区文化和治理模式上。

Niko 在文章中反复使用 “我们 (we)” 这个词,而这个“我们”,指代的通常是整个 Rust 社区和所有贡献者。他乐于讲述 ACM 获奖名单难产的故事,以此来证明 Rust 的成功是“集体所有”的。

这种对话式的风格,与其开放的 RFC (Request for Comments) 流程是一致的。任何重大的语言变更,都必须经过漫长、公开的社区讨论。Rust 的进化,是一个由全球开发者共同参与、自下而上推动的过程。

所以,当你阅读 Rust 的“官方之声”时,你其实是在了解一个公开的设计讨论。它邀请你一起思考“什么是更好的软件”,并相信通过集体的智慧,能够不断接近理想的答案,哪怕过程充满思辨与权衡。

Go 的“工程化叙事”——在现实世界中追求简洁

现在,让我们切换到 Go 的世界。

如果你阅读 Russ Cox 或 Rob Pike 的文章,会立刻感受到一种截然不同的气息:问题驱动,逻辑清晰,方案明确。

Go 的文章,几乎总是以一个具体的、待解决的工程问题开篇。无论是包管理的混乱,还是泛型的缺失,他们会用严谨的逻辑,一步步地分析问题背景、评估现有方案,最终给出一个经过深思熟虑的官方提案。

这里没有宏大的比喻,取而代之的是清晰的数据、代码示例和对各种边界情况的分析。他们追求的不是思想的深邃,而是方案的“显而易见 (obvious)”

这种风格背后,是对另一个根本事实的坚守:大规模软件工程的核心挑战,是控制复杂性。

Go 的设计哲学,可以概括为“规定性的简单性 (prescriptive simplicity)”。它相信,通过提供一个更小的工具集,并制定严格的工程规范(如 gofmt),可以显著降低团队协作的认知成本,从而提升整体生产力。

Go 团队清楚,每一个新加入语言的特性,都是一种“复杂性预算”的支出。因此,他们对此极为审慎。泛型这个功能,Go 社区讨论了近十年,核心团队才最终拿出一个他们认为足够简单、不会破坏 Go 核心价值的方案。

在这种哲学下,Go 的文章读起来就像一份工程白皮书。它不展示所有可能的路径,而是直接告诉你那条经过专家团队验证过,被认为最平坦、最宽阔的道路。它传递的核心信念是:“相信我们,这条路最简单直接,最能规模化。”

这种“决断感”也体现在 Go 的治理模式上。

Go 的演进,更多是由一小群核心专家(很多来自 Google)主导的“自上而下”模式。虽然他们也会通过提案流程征求社区反馈,但最终的决策权高度集中。文章中,“我们 (we)”这个词,更多时候指代的是 Go 核心团队。

这种模式保证了 Go 的稳定性和向后兼容性,但也意味着语言的演进会更加保守。Go 的进化,更像是一系列精准解决现实问题的“外科手术”,而非一场开放式的探索。

所以,当你阅读 Go 的“官方之声”时,你其实是在看一份来自顶级工程团队的技术报告。它不侧重于邀请你参与设计权衡,而是直接为你提供一个经过验证的、旨在解决你当前问题的最佳实践。

文字的岔路口,语言的未来

这两种截然不同的叙事风格,如同两条岔路,清晰地预示了 Rust 和 Go 在未来演进道路上的不同选择。

Rust 的未来,将是一场对语言能力边界的持续探索。

它会继续在“可扩展编译器”、“语言互操作”、“函数Traits”等领域,尝试为开发者提供更强大的“赋能”工具。它的进化过程将继续是思辨性的、社区驱动的,充满思想碰撞。这也可能意味着,它的学习曲线在短期内不会变得平缓,而重大的新特性,依然需要较长的讨论和共识周期。

Go 的未来,则是一场稳健的工程建设。

它将继续保持克制和实用主义。下一个重大变更,几乎可以肯定是为了解决大规模工程中出现的下一个具体痛点(比如,可感知NUMA的GC、对SIMD指令的内置支持等)。Go 会极力捍卫其“简单”的核心价值,避免任何可能导致语言心智模型复杂化的改动。它的进化将是可预测的、问题驱动的。

在这里,我想提出一个或许能概括两者差异的观点:

Rust 试图通过提供复杂的工具,让你成为一个思考更周全、能力更强的程序员;而 Go 则试图通过提供简单的工具,让你立即成为一个在团队中高效协作的程序员。

一个是授你以渔,但渔具复杂;一个是直接给你一条标准化的、足够好用的鱼竿。

小结:开发者如何选择?——聆听与你共鸣的声音

到这里,我们已经清晰地看到,Rust 和 Go 的“官方之声”背后,是两套截然不同的世界观。

  • Rust 的世界观是赋能与驾驭: 它相信通过赋予开发者强大的工具,可以驾驭固有的复杂性,构建出理论上最优的软件。
  • Go 的世界观是约束与纪律: 它相信通过设定清晰的约束,可以消除不必要的复杂性,构建出工程上最稳健、最易于维护的软件。

那么,作为开发者,我们该如何选择?

我的建议是,超越那些性能跑分和“Hello World”的语法对比,去读一读他们核心团队的文章吧

问问你自己:

  • 你是更倾向于一场开放式的、关于“可能性”的哲学讨论,还是更需要一份逻辑严密、直指问题核心的工程方案?
  • 你是在寻找一个与你一同探索复杂问题的“伙伴”,还是一个为你提供清晰建造指南的“总工程师”?

这个问题的答案,可能比任何技术指标都更能决定你的项目能否成功、你的团队是否快乐。

因为最终,我们选择一门编程语言,远不止是选择一个编译器和一套库。我们是在选择一个与之共鸣的社区,一套解决问题的世界观,一种塑造我们思维方式的技术文化。

而这一切,早已写在了他们的字里行行间。

你,听到了哪种声音的回响?


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

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

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

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

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


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

从 Rob Pike 的提案到社区共识:Go 或将通过 new(v) 彻底解决指针初始化难题

本文永久链接 – https://tonybai.com/2025/08/17/create-pointer-to-simple-types

大家好,我是Tony Bai。

在 Go 中创建一个指向基本类型(如 int 或 string)的指针,为何比创建一个指向结构体的指针更繁琐?这个长期存在的“人体工程学”问题,由 Go 语言的共同创造者之一 Rob Pike 在提案 #45624 中再次带入公众视野,并由此引发了一场长达数年、充满深度思辨的社区大讨论。最终,在权衡了多种方案的利弊后,社区逐渐形成共识,Go 提案委员会倾向于接受 new(v) 语法。本文将和大家一起回顾这场关于指针初始化的“十年之辩”,深入探讨各种方案的优劣,并解读为何 new(v) 可能成为最终赢家。

背景:一个困扰开发者多年的“小”问题

在 Go 中,我们可以用 p := &S{a: 3} 这样简洁的语法,一步到位地创建一个指向已初始化结构体的指针。但如果我们想创建一个指向 int 值 3 的指针,就必须写成:

a := 3
p := &a

这种不对称性在处理大量使用指针来表示“可选”字段的场景时(例如,与 JSON、Protobuf 或 AWS SDK 交互),会变得异常繁琐。开发者往往不得不在项目中定义或引入大量的辅助函数,如:

func StringPtr(s string) *string {
    return &s
}
// 还有 Int64Ptr, BoolPtr, Float64Ptr...

正如 @adonovan 在提案讨论中通过代码分析所展示的,这种模式在 Go 开源生态中极为普遍,存在数千个这样的辅助函数和数十万次的调用。这清晰地表明,语言层面提供一个更简洁的解决方案是众望所归。

方案之争:一场关于语法、语义与哲学的辩论

Rob Pike 的提案及其漫长的讨论过程,涌现了多种解决方案,每种方案都代表了一种不同的语言设计哲学。

方案一:扩展 & 操作符

这是最直观的想法,主要有两种变体:

  1. &T(v) (让类型转换变得可寻址): p := &int(3)。这是 Rob Pike 最初提出的方案之一。它利用了“类型转换必然会创建新值”这一语义,逻辑自洽。
  2. &v (让非地址表达式变得可寻址): p := &3 或 p := &time.Now()。这个方案更通用,但也最危险。正如 rsc 和其他核心成员指出的,这会产生严重的歧义。例如,&m[k] 在 m 是 slice 时是取地址,但在 m 是 map 时却变成了“拷贝值并取地址”,这会引入大量难以察觉的 bug。

由于存在严重的“最小惊动原则”问题,扩展 & 的方案最终未被采纳。

方案二:引入新的泛型内建函数

随着 Go 1.18 泛型的引入,一个显而易见的解决方案是提供一个泛型辅助函数。

// 可以是内置的,也可以是开发者自己写的
func ptr[T any](v T) *T {
    return &v
}

// 使用方式:
p := ptr(3)
p2 := ptr(time.Now())

这个方案得到了许多开发者的支持,因为它无需对语言规范做任何大的改动。然而,它的缺点也很明显:

  • 命名之争:应该叫 ptr, ref, addr, newOf 还是 varOf?每种名称都有其支持者和反对者。例如,ptr 和 ref 可能会让人误以为是取现有变量的引用,而不是创建一个新的拷贝。
  • 标准库位置:这样一个基础的函数应该放在哪里?builtin?还是一个新的标准库包?这本身就是一个难题。

方案三:扩展 new 内建函数 (最可能的胜出者)

这是提案的核心,也是最终获得Go提案委员会青睐的方向。它同样有几种变体:

  1. new(T, v):new 接受一个可选的第二个参数用于初始化。例如 p := new(int, 3)。这非常明确,但缺点是类型 T 往往是冗余的,显得很“啰嗦”,例如 new(time.Duration, time.Second)。
  2. new(v):new 可以直接接受一个值,并根据值的类型推断出要分配的指针类型。例如 p := new(3) 会创建一个 *int。这是最简洁的方案。

new(v) 的核心争议与共识

new(v) 的主要争议在于语法歧义。当看到 new(pkg.X) 时,读者无法仅从语法上判断 pkg.X 是一个类型(new(T))还是一个常量值(new(v))。

然而,经过深入讨论,提案委员会认为:
* 这种歧义在实践中问题不大,因为绝大多数情况下,上下文足以让开发者区分类型和值。
* 相比于 &v 带来的严重语义混乱,new(v) 的语法歧义是次要的、可接受的。
* new 这个词本身就清晰地传达了“创建新事物”的意图,避免了 & 操作符的“拷贝还是引用”的混淆。
* 考虑到 new(T) 的使用频率远低于 &T{},将其“回收”并赋予更强大的功能,是对语言的一次有益的“清理”。

最终,提案委员会倾向于接受 new(expr) 的形式。

new(expr) 将如何工作

根据讨论的共识,未来的 new(expr) 将遵循以下规则:

  • 基本用法: p := new(3) 将创建一个 *int,其值为 3。s := new(“hello”) 将创建一个 *string,其值为 “hello”。
  • 类型推断: 对于无类型常量,将使用 Go 的默认类型规则(例如,整数默认为 int,浮点数默认为 float64)。
  • 显式类型: 如果需要指定不同于默认的类型,需要使用类型转换:p64 := new(int64(3))来创建一个int64类型变量p64,而不是默认的int指针类型变量。
  • 无上下文类型推断: new(v) 不会根据赋值的上下文来推断类型。例如,var p *int64 = new(3) 将会编译失败,因为 new(3) 的类型是 *int,不能赋值给 *int64。

结论:小改动,大便利

从 Rob Pike 最初的提案,到社区长达数年的激烈辩论,new(v) 的最终可能胜出是 Go 语言演进过程的一个缩影。它通过一个微小但精心设计的语法扩展,解决了困扰社区多年的一个普遍痛点。

这个决策过程本身,也充分体现了 Go 团队的设计哲学:

  1. 优先考虑语言的一致性和无歧义性,因此拒绝了看似更简洁但充满陷阱的 &expr 方案。
  2. 在不破坏兼容性的前提下,勇于重塑旧有特性,将使用率不高的 new 重新利用,赋予其更强大的生命力。
  3. 充分倾听并分析社区的真实数据,@adonovan 的大规模代码分析为该功能的需求提供了强有力的数据支撑。

虽然我们仍需等待该提案在未来某个 Go 版本中正式落地,但可以预见,当它到来时,我们代码库中那些重复的 Ptr 辅助函数将成为历史。这正是 Go 语言持续进化、不断提升开发者幸福感的魅力所在。


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

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

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

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

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


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

如发现本站页面被黑,比如:挂载广告、挖矿等恶意代码,请朋友们及时联系我。十分感谢! Go语言第一课 Go语言进阶课 Go语言精进之路1 Go语言精进之路2 Go语言第一课 Go语言编程指南
商务合作请联系bigwhite.cn AT aliyun.com

欢迎使用邮件订阅我的博客

输入邮箱订阅本站,只要有新文章发布,就会第一时间发送邮件通知你哦!

这里是 Tony Bai的个人Blog,欢迎访问、订阅和留言! 订阅Feed请点击上面图片

如果您觉得这里的文章对您有帮助,请扫描上方二维码进行捐赠 ,加油后的Tony Bai将会为您呈现更多精彩的文章,谢谢!

如果您希望通过微信捐赠,请用微信客户端扫描下方赞赏码:

如果您希望通过比特币或以太币捐赠,可以扫描下方二维码:

比特币:

以太币:

如果您喜欢通过微信浏览本站内容,可以扫描下方二维码,订阅本站官方微信订阅号“iamtonybai”;点击二维码,可直达本人官方微博主页^_^:
本站Powered by Digital Ocean VPS。
选择Digital Ocean VPS主机,即可获得10美元现金充值,可 免费使用两个月哟! 著名主机提供商Linode 10$优惠码:linode10,在 这里注册即可免费获 得。阿里云推荐码: 1WFZ0V立享9折!


View Tony Bai's profile on LinkedIn
DigitalOcean Referral Badge

文章

评论

  • 正在加载...

分类

标签

归档



View My Stats