news 2026/4/22 12:56:15

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/4/18 15:20:02

ModbusRTU从机应答延迟问题实战分析与优化

ModbusRTU从机应答延迟问题实战分析与优化:从“卡顿”到流畅的工程突围一个困扰工程师的真实场景某日,产线上的PLC主站突然频繁报出“通信超时”,监控系统显示多个温湿度传感器(ModbusRTU从机)响应异常。现场排查发现&…

作者头像 李华
网站建设 2026/4/20 14:27:10

核心要点:ESP32和Arduino通信接口对比详解

ESP32与Arduino通信接口深度对比:从原理到实战的完整指南在物联网和嵌入式开发的世界里,ESP32和Arduino Uno是开发者最熟悉的两个名字。一个以无线能力见长,一个以易用性著称。但当项目复杂度上升——比如你需要同时连接多个传感器、驱动显示…

作者头像 李华
网站建设 2026/4/20 19:04:25

LangFlow婚礼致辞生成器实用案例

LangFlow婚礼致辞生成器实用案例 在一场婚礼上,最动人的瞬间之一,莫过于亲友站上台前,用真挚的话语讲述新人的爱情故事。然而,很多人面对“说点什么”时却犯了难:既怕说得太生硬,又担心不够感人&#xff1b…

作者头像 李华
网站建设 2026/4/21 12:20:24

LangFlow历史事件时间轴自动生成工具

LangFlow:让历史时间轴自动生成变得触手可及 在教育、出版或内容创作领域,我们常常需要从一段杂乱的历史叙述中梳理出清晰的时间脉络。过去,这项工作要么依赖人工逐条提取,要么由开发人员编写定制脚本进行信息抽取——费时、易错且…

作者头像 李华
网站建设 2026/4/20 16:00:00

LVGL教程:消息框msgbox控件应用场景解析

LVGL实战精讲:用好消息框控件,让嵌入式交互更专业你有没有遇到过这样的场景?设备突然黑屏重启,用户一脸茫然;点击“删除配置”按钮后数据瞬间清空,毫无挽回余地;固件升级中途断电,系…

作者头像 李华
网站建设 2026/3/31 11:08:17

公安机关PDT数字集群信号覆盖介绍

公安机关PDT数字集群通信系统是以话音为主的无线指挥通信系统,是目前指挥调度、救灾抢险、交通管理、社会治安、重大保卫活动以及日常警务必不可少的重要无线通信手段。国内PDT建设主要集中为基站进行大范围的覆盖以及公安消防等保卫单位内部保障信号覆盖&#xff0…

作者头像 李华