news 2026/6/23 15:39:46

Go1.26 新特性:new(expr) 终于来了,创建指针简单了!

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Go1.26 新特性:new(expr) 终于来了,创建指针简单了!

大家好,我是煎鱼。

今天给大家分享一个 Go1.26 即将带来的实用新特性——new(expr)表达式支持。

相信写过 Go 的同学都有过这样的经历:创建一个结构体指针很简单,但要创建一个基本类型的指针就得多写好几行代码。还是挺烦人的。

这个特性能解决日常开发中的小痛点。

背景

在 Go 中,如果我们想创建一个指向结构体的指针,可以这样写:

type Person struct { name string } p := &Person{name: "alice"}

非常简洁优雅。但如果我们想创建一个指向基本类型值的指针呢?

就得这么写:

n := 42 p := &n

或者用new函数:

p := new(int) *p = 42

看起来就很不协调对吧?为什么创建复合类型的指针可以一步到位,而基本类型就得多写一个临时变量或者两行代码?

这个问题其实在社区里讨论了很久。早在 2014 年的 issue #9097[1]就有人提出过,但当时被驳回了。

为什么不能直接写 &3?

可能有同学会问:为什么不直接支持p := &3这种写法呢?

问题就出在类型系统上。在 Go 中,数字字面量3是一个无类型常量(untyped constant),它本身没有确定的类型。只有在赋值或者运算时,编译器才会根据上下文推断出具体类型。

如果允许&3这种写法,编译器就不知道该分配什么类型的内存空间 —— 是intint64还是float64

这会带来类型歧义,所以这条路走不通。

新提案:扩展 new 函数

Go 团队最终采纳的方案是:让new函数不仅可以接受类型参数,还可以接受表达式参数。

快速例子:

p1 := new(int, 3) p2 := new(rune, 10) p3 := new(Weekday, Tuesday) p4 := new(Name, "unspecified") ... and so on

语法规则

新的new函数行为如下:

  • 如果参数expr是一个类型为 T 的表达式,或者是一个默认类型为 T 的无类型常量表达式,那么new(expr)会分配一个类型为 T 的变量,将其初始化为expr的值,并返回其地址(类型为*T)

  • 如果参数是类型 T,那么new(T)会分配一个初始化为零值的 T 类型变量(这是原有行为)

简单来说,就是new现在既能接受类型,也能接受值了。

代码示例

基本类型指针

以前我们得这么写:

// Go 1.25 n := 42 p1 := &n fmt.Println(*p1) // 42 s := "go" p2 := &s fmt.Println(*p2) // go

现在可以直接:

// Go 1.26 p1 := new(42) fmt.Println(*p1) // 42 p2 := new("go") fmt.Println(*p2) // go
复合类型指针

对于切片这类复合类型也同样适用:

// Go 1.25 s := []int{11, 12, 13} p1 := &s fmt.Println(*p1) // [11 12 13] type Person struct{ name string } p2 := &Person{name: "alice"} fmt.Println(*p2) // {alice}

新写法:

// Go 1.26 p1 := new([]int{11, 12, 13}) fmt.Println(*p1) // [11 12 13] type Person struct{ name string } p2 := new(Person{name: "alice"}) fmt.Println(*p2) // {alice}
函数返回值指针

这个场景以前特别麻烦:

// Go 1.25 f := func() string { return "go" } v := f() p := &v fmt.Println(*p) // go

现在一行搞定:

// Go 1.26 f := func() string { return "go" } p := new(f()) fmt.Println(*p) // go

需要注意的是,传入nil仍然是不允许的:

p := new(nil) // 编译错误

实现原理

其实这个特性的实现思路很简单。当你写:

p := new(42)

编译器会将其转换为类似这样的操作:

var _tmp = 42 p := &_tmp

或者等价于:

p := new(int) *p = 42

也就是说,new(expr)本质上是为非可寻址的表达式显式分配存储空间,然后返回其地址。

这样就统一了创建指针的方式,不管是基本类型还是复合类型,都可以用类似的语法。

社区讨论中的另一个方案

其实在 proposal 讨论过程中,Rob Pike 还提出了另一个有趣的方案:让类型转换变得可寻址。

比如可以这样写:

p1 := &int(3) p2 := &rune(10) p3 := &string("hello")

这个方案的逻辑是:类型转换必然会创建新的存储空间(因为要改变类型),所以让它可寻址是合理的。

不过最终 Go 团队选择了扩展new的方案,可能是考虑到:

  1. new函数的语义本身就是"分配并初始化",扩展它更自然。

  2. 避免引入新的语法歧义。

  3. 保持&运算符语义的一致性。

实际应用场景

这个特性虽然看起来简单,但在实际开发中还是挺有用的。比如:

1. 配置选项

很多第三方库的配置结构体中会有指针类型的字段,用来区分"未设置"和"设置为零值":

type Config struct { Timeout *int MaxRetry *int } // Go 1.25 timeout := 30 config := Config{ Timeout: &timeout, MaxRetry: new(int), // 只能用 new(int) 表示 0 } // Go 1.26 config := Config{ Timeout: new(30), MaxRetry: new(0), }

2. 测试代码

在单元测试中构造测试数据时,这个特性能让代码更简洁:

testCases := []struct { input *int expected string }{ {new(42), "success"}, {new(0), "zero"}, {nil, "nil"}, }

3. 内联指针创建

在函数调用时需要传指针参数:

// Go 1.25 func process(val *string) {} s := "data" process(&s) // Go 1.26 process(new("data"))

总结

new(expr)这个特性解决了 Go 中创建基本类型指针时的不便,让代码更简洁一致。虽然改动不大,但确实提升了开发体验。

这个特性将会在 Go1.26 版本正式发布,由 Alan Donovan、Ian Lance Taylor、Rob Pike 等核心团队成员推动完成。

对于我们 Go 开发者来说,以后写代码可以少定义临时变量了,代码也会相对干净些。

花了 11 年啊。绝了,真的服了。

参考资料

[1]

#9097:https://github.com/golang/go/issues/9097

关注和加煎鱼微信,

一手消息和知识,拉你进技术交流群👇

你好,我是煎鱼,出版过 Go 畅销书《Go 语言编程之旅》,再到获得 GOP(Go 领域最有观点专家)荣誉,点击蓝字查看我的出书之路

日常分享高质量文章,输出 Go 面试、工作经验、架构设计,加微信拉读者交流群,和大家交流!

原创不易 点赞支持

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/6/23 18:09:24

elasticsearch可视化工具实现集群负载均衡监控教程

用可视化工具给 Elasticsearch 集群“把脉”:如何实时监控负载均衡?你有没有遇到过这样的场景?凌晨两点,告警突然炸响:“某节点 CPU 持续 98%!”你火速登录服务器,curl -XGET http://es-node:92…

作者头像 李华
网站建设 2026/6/23 13:07:36

OrCAD与Allegro协同工作:无缝对接设计流程

OrCAD与Allegro协同设计实战:从原理图到PCB的无缝跃迁在高速、高密度电子系统开发中,一个微小的设计失误可能引发整板返工,甚至延误产品上市周期。如何确保从电路构想到物理实现的每一步都精准无误?答案在于——前端与后端工具的深…

作者头像 李华
网站建设 2026/6/23 9:29:22

从零实现无乱码开发环境:Keil + UTF-8-BOM配置教程

一劳永逸解决Keil中文乱码:UTF-8-BOM实战配置全攻略你有没有遇到过这样的场景?写了一段精心组织的中文注释,保存后重新打开,结果变成“锘挎偍濂藉”、“閿熸枻鎷稟”这种鬼画符;或者团队协作时,同事打开你的…

作者头像 李华
网站建设 2026/6/23 13:47:11

调整IDE设置以避免代码自动换行

方案1:调整代码行长度限制(推荐) IntelliJ IDEA: 打开设置: File → Settings (Windows/Linux) 或 IntelliJ IDEA → Preferences (Mac)导航到:Editor → Code Style → Java在 Wrapping and Braces 标签页中&#xff…

作者头像 李华