创建指向简单类型的指针的表达式

新提案:创建指向简单类型的指针的表达式

大家好,我是煎鱼。

在 Go 语言中,我们经常要声明各种变量,再进行赋值,才能开始写程序。

常见的会是使用 new 或 make,甚至会有技术文章《Go 面试题: new 和 make 是什么,差异在哪?》探讨什么 new 和 make 的区别。

也有特例,是直接使用 &S{} 来作为构建指向结构体的指针的方法。这奇怪点是,只有结构体可以用,分配方式是半隐藏的。

背景

这可能叫做创作这门语言的 Go 语言之父 Rob Pike 对自己创作的语法产生了奇妙的疑惑。

在新提案《proposal: expression to create pointer to simple types》中提出了这个问题。

问题

他发现结构体这种分配方式,更容易。而创建一个简单类型的指针,会更麻烦一些。如下:

// 结构体
p := &S{a:3}

// 简单类型
a := 3
p := &a

也就是在一门语言中不同的数据类型的处理方式都不一样,而且简单类型比复合的结构体更难初始化变量。

新建议

第一种

第一种方式是给函数 new 增加可选参数。函数签名如下:

new(typeOfExpression, Expression)

演示案例如下:

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

这样可以将 Go 的多种数据类型方式完全纠正过来,实现统一。但是内置函数 new 会变的冗长,会有的人不喜欢。

第二种

第二种方式是内置新的可寻址方式来解决。可能有小伙伴以为是:

p := &3

并不是,这样是没法知道 3 是什么类型,自然编译器也无法识别,这个脑洞没法实现。

演示案例如下:

p1 := &int(3)
p2 := &rune(10)
p3 := &Weekday(Tuesday)
p4 := &Name("unspecified")

这样相当于给所有数据类型增加了一个 & 转换的过程,让他们能够进行寻址。

讨论

社区内大家对此议论纷纷,给出了各种方案。 我梳理了一下,基本分为以下三类建议:

  • 可以给基本类型加初始化,例如:&int{3}&bool(true)&string("brains"),效果和 &S{} 一样。
  • 可以改造函数 new,例如:new(int(3)),也能解决基本类型的两行声明。
  • 可以利用泛型,加一个函数实现类似的效果,例如:func NewOf[T any](v T) *T

甚至还有人唱反调,认为社区中有其他人提出,却不被受重视。但是 Rob Pike 一提出,就能够一呼百应。

(相当于是嘲讽了…)

总结

我们针对平时 Go 编程中常常用到的取地址场景进行了讲到,不说的话,其实很多同学没发现这个细节:也就是结构体可以取,但是基本类型不能。

Go 核心团队也在不断地想要统一和优化这个用法。加上原有的提案上的两种方式,其实就有 5 类建议了,你比较认可哪种呢?

本图书由 煎鱼 ©2022 版权所有,所有文章采用知识署名-非商业性使用-禁止演绎 4.0 国际进行许可。