指针的创建及赋值

&*
nil
new&
&

这里就引出一个问题,假如一个结构体的字段是个指针,那么在初始化该字段时就不能直接写字面量了,

解决办法有两个,

  • 创建中间变量,通过变量来赋值给结构体的这个指针变量
  • 创建工具方法,专门用来将字符串,数字及布尔值这种原始类型转成指针

值传递

因为 Go 中函数的参数是值传递,所以,当指针作为参数时,复制的是指针,而不是指针所指向的对象。所以,

nilnil

首先第一点,看这个示例:

xpnilppixnil
nil

再看第二点,

除非是在必要的时候,比如处理 JSON,否则尽量避免使用指针,因为它使得数据流向不明确,并且带来额外的垃圾回收成本。

当然,在一些极限情况下使用指针是有收益的,比如函数入参是个比较大的结构体,使用指针传递或进行返回可提高性能,因为对于任何数据类型来说,指针大小是恒定的。

Map & Slice

两者的背后实现都是指针,所以在之前的内容中有涉及到说函数体里对两者的修改都会影响其原来的值,这就不奇怪了。

正因为如此,不建议使用 map 作为函数的入参入返回,以及作为 API 的返回。API 中应该使用结构体,无论是文档还是字段限制都会更加清晰。

append

具体来说,slice 的实现是一个包含三个字段的结构体,分别是长度,容量及指向存储的指针:


当传递到函数内,参数复制后的结果为:


appendlencap
caplenlen


cap


因此,slice 在传到函数体中,只能被修改存在的元素,而无法进行尺寸的变化。好的做法是尽量不要在函数内对 slice 进行变更,特别是在 API 设计时。

int