苦等11年,Go 终于决定通过复合字面量的提案了,开发者直呼yyds。

举报
golang学习记 发表于 2026/05/14 16:09:46 2026/05/14
【摘要】 2015年10月6日,一个普通的周二。一位名叫 neild 的 Go 贡献者在 GitHub 上提交了一个看似不起眼的关于复合字面量的提案,标题很克制:“spec: type inferred composite literals”。提案的意思就是希望让Go代码更加简单:能不能让我少写几个字?比如这样:// 以前var x []string = []string{"a", "b", "c"}...

2015年10月6日,一个普通的周二。

一位名叫 neild 的 Go 贡献者在 GitHub 上提交了一个看似不起眼的关于复合字面量的提案,标题很克制:“spec: type inferred composite literals”。

image.png

提案的意思就是希望让Go代码更加简单:能不能让我少写几个字?

比如这样:

// 以前
var x []string = []string{"a", "b", "c"}

// 以后(如果提案通过)
var x []string = {"a", "b", "c"}

看起来只是省了几个字符,对吧?

但就是这个"小想法",在 Go 社区里吵了整整 11 年。

直到 2026 年 4 月 15 日,提案状态终于从 “Likely Accept” 变成了 “Accepted” 🎉

image.png

一场"删字符"引发的哲学战争

你可能会想:不就是少写几个类型名吗?至于吵 11 年?

至于。

因为这个问题背后,藏着 Go 语言最核心的设计哲学冲突:显式优于隐式,到底应该坚持到什么程度?

让我讲个真实故事。

三年前,我带一个新人写 Go。他兴奋地用上了各种"简洁写法":类型推断、省略返回值变量名、匿名结构体……代码确实短了 30%。但两周后,他离职了。接手代码的我,花了整整两天才搞明白某个函数到底返回的是什么类型。

那一刻我突然理解了为什么 Go 团队当初那么"固执":

“宁可多写两行,也要让三个月后的自己能看懂。”

为什么这个提案值得吵 11 年?

让我用三个场景说明,为什么有人愿意为"少写几个字"坚持这么久。

场景一:函数参数的"结构体包装"模式

很多 Go 开发者都遇到过这种写法:

// 参数太多?包成结构体!
type Config struct {
    Host string
    Port int
    Timeout time.Duration
}

func Connect(cfg Config) { ... }

// 调用时
Connect(Config{
    Host: "localhost",
    Port: 8080,
    Timeout: 30 * time.Second,
})

但如果能省略类型呢?

func Connect(cfg struct {
    Host string
    Port int
    Timeout time.Duration
}) { ... }

Connect({
    Host: "localhost",
    Port: 8080,
    Timeout: 30 * time.Second,
})

是不是清爽多了?特别是当这个结构体只在这个函数里使用时,单独定义一个类型反而增加了认知负担。

场景二:Channel 通信的"轻量元组"

这是我最想要的特性:

ch := make(chan struct {
    value string
    err   error
})

// 以前
ch <- struct {
    value string
    err   error
}{value: "result", err: nil}

// 以后(梦想中)
ch <- {value: "result", err: nil}

看到没?这本质上是在用匿名结构体模拟"元组"。虽然没有真正的 tuple 语法糖,但这种写法已经能让代码优雅不少。

场景三:Protobuf 的"嵌套地狱"

如果你写过 gRPC 服务,一定懂这种痛:

req := &mypb.Request{
    Options: &mypb.Request_Options{
        Filter: &mypb.Request_Options_Filter{
            Conditions: []*mypb.Condition{
                {Field: "age", Op: ">", Value: 18},
            },
        },
    },
}

如果每一层都能省略类型……嗯,我不敢想,怕笑出声。

反对派的声音:可读性真的不重要吗?

当然不是。

提案的反对者(包括 Go 核心团队成员)提出了几个非常有力的观点:

第一,"省略类型"会让代码失去"自文档"特性。

当你看到 []string{"a", "b"},你立刻知道这是一个字符串切片。但看到 {"a", "b"},你需要往上找变量声明,或者依赖编辑器的类型提示。

第二,歧义问题。

const A = "A"
var x struct{ A int }
var m map[string]int

x = {A: 1}  // 这是给结构体字段赋值?
m = {A: 1}  // 还是给 map 的键赋值?

虽然提案明确说 {A: 1} 会根据目标类型解析(A 是变量名而非字符串),但这种"上下文依赖"本身就增加了理解成本。

第三,工具链的挑战。

Go 的一大优势是"开箱即用"的工具体验。但如果类型可以省略,gopls、gofmt、staticcheck 等工具都需要重新思考:

  • 代码补全时,要不要自动补上被省略的类型?
  • 格式化时,要不要"智能"地恢复某些类型?
  • 重构时,如何保证省略类型的代码不会"静默出错"?

这让我想起海德格尔的警告:“技术的本质不在于技术本身。” 当我们讨论"要不要省略类型"时,本质上是在讨论:我们希望开发者与代码建立什么样的关系?

作为一个写过几十万行 Go 的开发者,我对这个问题的态度经历了三个阶段:

阶段一(新手期):“能少写就少写!简洁即正义!”

阶段二(踩坑期):“等等,这代码怎么看不懂了?是谁写的?哦,是我自己……”

阶段三(成熟期):“简洁很重要,但清晰更重要。关键是要有’可逆的简洁’。”

什么叫"可逆的简洁"?

就是:你可以选择省略类型让代码变短,但工具能一键恢复类型让代码变清晰。就像拍照时的"人像模式"——背景虚化是为了突出主体,但原图始终在那里,需要时随时能调出来。

这其实也是 Go 团队最终接受提案的关键前提:

“我们不希望鼓励人们在不该省略的时候省略类型,但我们也不知道如何自动判断’该不该’。所以,把选择权交给开发者,把’恢复类型’的能力交给工具。”

回到开头:为什么吵了 11 年,现在终于接受了?

我觉得有三个原因:

第一,生态成熟了。

2015 年,Go 的工具链还很基础。但现在,gopls 已经能提供强大的类型提示、跳转、重构能力。即使你省略了类型,编辑器也能"无感"地帮你补全上下文。

第二,使用场景更清晰了。

11 年的社区实践让大家明白:哪些场景省略类型真的能提升可读性(比如轻量结构体参数),哪些场景会适得其反(比如复杂嵌套的初始化)。经验比理论更有说服力。

第三,“接受"不等于"鼓励”。

提案通过后的评论很有意思:

“我们不会修改 gofmt 来自动移除类型,因为我们不知道什么时候该移除。”

这其实是一种很"Go"的智慧:提供能力,但不强制使用;相信开发者,但不纵容懒惰。

写到这里,我忍不住想:

为什么一个简单的"省略类型"功能,需要 11 年才能落地?

因为语言设计本质上是一个"熵减"过程。每增加一个特性,语言的复杂度就增加一分。而复杂度的代价,会由每一个使用者承担。

罗素在《西方哲学史》里说过:“参差多态乃是幸福本源。” 但编程语言不一样——一致性才是效率本源。

当你允许 {A: 1} 既可以赋值给 struct{A int},也可以赋值给 map[string]int(A 是变量),你就引入了"上下文依赖"。而上下文依赖,是认知负担的源头。

所以,11 年的争论,不是在争"能不能少打字",而是在争:我们愿意为简洁付出多少认知成本?

写在最后

苏格拉底说:“认识你自己。”

我觉得这句话送给编程语言设计者也合适:认识你的用户。

新手需要显式,因为他们在建立心智模型;
专家需要简洁,因为他们已经在脑中构建了类型图谱;
团队需要一致,因为协作的本质是降低沟通成本。

Go团队表示:按照目前的开发周期,这项功能不太可能进入 Go 1.27,我们的目标是 Go 1.28。尽管编译器层面的实现其实相当简单,但这项改动会对工具链产生重大影响,我们需要仔细考虑在 gopls 中的兼容与体验方案。

不过也要心急同时又有趣的网友和Go团队battle表示,既然 gopls 是独立的发布周期,而且这个语言特性的实现又 “相当简单”…… 那我们能不能想个办法把它放进 Go 1.27 里?工具链可以按自己的节奏慢慢追赶,但至少让我们这些开发者能早点玩上这个超棒的新特性嘛。

因为语言和工具应该是解耦的关系,语言特性该先发,工具后续跟上,而不是反过来让工具决定语言什么时候能发布。

但是Go团队表示坚决反对,新版 IDE ,比如Goland如果无法适配最新正式版 Go 语言,会带来极差的用户体验。而且针对 Go 1.27 里其他的语言变更,我们本身还有不少工具适配工作没做完,所以只能委屈人类,大家只能再老老实实手写类型名,继续熬半年。

还有热心的网友希望在有了这个功能之后,可以给fmt加一个功能,让它自动把省略的类型补回来。即使在在 AI 时代,可读性远比少敲几下键盘重要得多。

在我看来,这种关于简洁性和可读性,其实任何一门发展的语言都会遇到,Go 允许简化书写,不代表可以把关键类型信息全部隐去。类型本身是代码的语义骨架,是给阅读者、给工具、给后续维护者的「语义路标」。全都省略,看似代码更短,实则砍掉了必要的信息支撑,从 “简洁” 滑向 “晦涩”。

维特根斯坦在《逻辑哲学论》早就提醒我们:语言的模糊,必然带来思想的混乱,一切伟大的表达,都以直白易懂为最高准则;绕弯子与刻意隐晦,都是平庸的掩饰。。

这很像人生:年轻时我们追求"做减法",以为简洁就是高级;成熟后我们明白,真正的优雅,是在复杂中找到平衡。

所以,当你在未来的 Go 代码里看到 var x []string = {"a", "b"} 时,不必惊讶。

那不只是少写了几个字符,那是一个语言、一群开发者、11 年时间,共同找到的"刚刚好"。

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。