GO 语言的指针和地址值
go语言中的指针和地址值,在使用上常常具有迷惑性,主要是其特殊的*、&符号的使用,可能会让你摸不透,本文希望能讲清楚go语言的指针(pointer)和值(value)。
这里先简单的对指针和地址值概念做一个定义:
- 指针:指针是一个内存地址,代表了从何处找寻到实际值的一个位置
- 地址值:对象实际值对象信息
区别就比如一个房子的位置和实际房子
为什么我们需要一个值的指针?
这是因为go方法传递参数的方式导致的,go方法函数传递参数传递的是一个拷贝,看看下面的程序会输出什么?
type Student struct {
Name string
Age int
}
func main(){
student := Student{Name: "小红", Age: 8}
AddAge(student)
fmt.Println(student.Age)
}
func AddAge(s Student){
s.Age += 1
}
答案是8,而不是9,因为AddAge函数修改的是学生的一个备份,而不是原始的学生对象
如果你想正确正确给学生年龄增加的话,函数传递的需要是这个值的指针,如下所示:
func main(){
student := Student{Name: "小红", Age: 8}
AddAge(&student)
fmt.Println(student.Age)
}
func AddAge(s *Student){
s.Age += 1
}
需要注意的是,这里我们的指针传递的仍然是一个拷贝,比如,如果你将s赋值给另外一个指针地址,不会影响原有的指针,这点可以自行实践下。
应用考虑
那在使用go语言开发的时候,何时该用指针何时改用地址值呢?比如考虑以下场景:
- 一个本地变量的赋值
- 结构体中的一个字段
- 方法返回的值
- 方法的参数
- 一个方法的接收者
简单原则:当你不确定该使用哪种的时候,优先使用指针
复合类型的使用
如果考虑在数组、切片、map等复合对象中使用指针和值,比如:
a := make([]Student, 0)
//或者
b := make([]*Student, 0)
很多开发者会认为b会更高效,但是被传递的都是一个切片的拷贝,切片本身就是一个引用,所以这里被传递的其实没有什么区别。
总结
对于指针和地址值的使用,大家需要牢记的一点就是go数据传递的不可变性,活学活用此特点,在无状态函数中此特性非常有用。
网友评论