Go语言 为什么我会让一个导出的指针变量指向一个未导出的变量,在包级?

3ks5zfa0  于 2023-04-09  发布在  Go
关注(0)|答案(1)|浏览(106)

以标准库net/http为例,DefaultClient定义为:

var DefaultClient = &Client{}

然而,DefaultServeMux被定义为:

var DefaultServeMux = &defaultServeMux
var defaultServeMux ServeMux

为一个对象定义两个变量的意义是什么?它比简单的var DefaultServeMux = &ServeMux{}有什么好处?

bz4sfanl

bz4sfanl1#

DefaultServeMux部分是布拉德菲茨帕特里克做的优化,我将从comments on the CL中复制并重新格式化他和Matthew Dempsky之间的对话:

马修·登普斯基:

为了确保我理解,问题是做

var x = newFoo()

即使x未使用,也需要调用newFoo()
[***]布拉德·菲茨帕特里克:**
是的,这会产生:

var x *T

func init() {
  x = newFoo()
}

而且链接器似乎从来没有删除过init块,即使它们只分配给那些本来只会被读取的东西。

马修·登普斯基:

var x = &y
var y foo

跳过显式的初始化代码。所以如果x没有被使用,它可以是死代码,沿着所有类型foo的相关代码一起被删除?
[***]布拉德·菲茨帕特里克:**
是的
我已经检查了从最新的源代码(commit 4f4a9c7fff)编译的go二进制文件的大小,我发现那个提交的变化有很大帮助,但是var DefaultServeMux = &ServeMux{}稍微好一点。见下表:
| 执行|go二进制文件的大小|
| --------------|--------------|
| var DefaultServeMux = NewServeMux()|15870476|
| var DefaultServeMux =&defaultServeMux;var defaultServeMux ServeMux|15864704(-5772)|
| var DefaultServeMux = &ServeMux{}|15864696(-5780)|

更新

在创建提交时,我试图找出var DefaultServeMux = &defaultServeMux; var defaultServeMux ServeMuxvar DefaultServeMux = &ServeMux{}之间的区别(回到go1.7).但是我在我的机器上编译go1.12失败了,所以我放弃了.我找到的是从go1.13到现在(devel go1.21-4f4a9c7fff),这两种实现在对go二进制文件大小的影响方面几乎相同。下面是结果(我的环境是go1.20.3 linux/amd64,我用./make.bash编译了二进制文件):
| git标签|var DefaultServeMux = &defaultServeMuxvar defaultServeMux ServeMux|var DefaultServeMux = &ServeMux{}|三角洲|
| --------------|--------------|--------------|--------------|
| go1.13 |15083862|15083862|0|
| go1.14 |15323624|15323624|0|
| go1.15 |14272775|14272775|0|
| go1.16 |14068974|14068982|+8|
| go1.17 |14022237|14022237|0|
| go1.18 |14545517|14545517|0|
| go1.19 |15302909|15302909|0|
| go1.20 |15579106|15579106|0|
| 4f4a9c7fff|15864704|小行星15864696|-8|

相关问题