这是一个很基础但是用起来可以变得很复杂的问题,我单从 Go 来说一个简单例子,不参考别的什么语言。
指针,顾名思义就是指向一个变量的值,看下面这段代码:
package main
import "fmt"
func reverse(p *[]int) {
for i, j := 0, len(*p)-1; i < len(*p)/2; i, j = i+1, j-1 {
(*p)[i], (*p)[j] = (*p)[j], (*p)[i]
}
}
func main() {
v := []int{1, 2, 3, 4}
reverse(&v)
fmt.Println(v)
} 这段代码你可以直接运行,其效果就是反转了 v 这个切片的内容,且并没有需要 reverse 函数返回修改好的切片,这就是指针的作用之一,下面我来解释。 主要从代码第 13 行 reverse(&v) 开始看, & 操作符生成了其操作数 v 的地址,地址类型为 *[]int (一个指针类型),于是我的 reverse 函数得到了这个指针。 接着来看 reverse 函数,在 Go 里面是没有指针运算的,但通过 * 操作符可以取得指针所对应的基本值然后进行操作。所以 *p 又变成了切片类型,然后通过一个循环就反转了切面所存储值的顺序。
简单总结:
&仅用于生成其操作数对应的地址,也就是用于生成指针*会出现在两个内容上:- 一个是类型,
* Type这样的格式代表了一个指针类型 - 一个是指针,
* Pointer这样的格式用于获取指针所对应的基本值
- 一个是类型,
最后再来看这段代码用指针的好处。当给一个函数传参时其实是会在内存空间复制一份后传递的,那么如果单纯使用切片类型传递的话,最后在 reverse 函数下处理后的切片和在 main 函数下的切片 v 是两个完全不同的,所以最后往往需要在 reverse 函数下返回处理好的切片给主函数。而像上述这种直接传递其指针,虽然也是会复制一份指针类型的变量后传递,但是却可以在 reverse 函数下通过传递过来的指针(地址)获取到原始的切片,并直接修改其内容。那么在数据内容很大的情况下就起到了节约程序开销的作用。