前言
今天是个好日子,适合来一篇文章庆祝一下,那么我要来点什么呢,想了一圈,不如就来聊一下Go中的那些指针的事情吧,毕竟指针这东西在Go中,还是挺有用的,那么话不多说,开始!—— 为了大茶缸。
什么是指针
指针 —— 一个指向另一个变量的地址的变量,这有点类似于一个指示牌的意思。
其实不是所有语言都提供了指针这个东西的,因为指针虽然有用,但同时它使用的时候也存在一些坑,例如在C里面的野指针,有些时候系统奔溃的原因也是由于指针造成的。
但是Go语言中的指针做了很好的处理,不会出现类似于迷途指针,这样的情况出现,意思也就是你跟着指示牌去找停车场的时候,不会把你给带到厕所去的意思。
Go中指针的使用
在Go中,要想使用指针,那么必须知道两个符号,那就是 & 和 * ,它们分别的作用是,一个可以提供内存地址,一个会提供内存所指向的值。
func show(a *int) {
fmt.Println(*a) // 66
}
func main() {
a := 66
show(&a)
}
上面的例子就是,通过&操作符,传入a的内存地址给到show函数,而在show函数中,则是在接收到内存地址之后,通过*操作符,把内存地址反向处理,找到这个内存地址所指向的值。
在Go里面,我们在定义一个指针的时候,同时也必须定义这个指针的类型,例如上面例子中的66,就是一个Int类型的指针,这样的话,当你向show函数传递一个非int类型的指针的时候,就会报错。
注意⚠️
我们可以看到在指针中的*,它存在这两种作用,一个是声明一个指针的类型,一个是对指针的变量进行一个解引用,而它们使用上的区别就是,一个是放置在类型前面,一个是防止在变量的前面。
指针的作用就是指向
从图片中,我们可以看出p是指向了a的内存地址0x0001的一个int类型的指针变量,而这个0x0001所指向的内存的值则是内存中的10。
普通指针
这里我来举个例子,假设在一个班级里面有一个班长,现任的班长是小红,前任班长是小明,下任班长是小黄,然后我们通过指针的方式,来指认班长的名字
func main() {
var Monitor *string
a := "xiao ming"
b := "xiao hong"
//c := "xiao huang"
Monitor = &a
fmt.Printf("Monitor name is %s\n", *Monitor) // Monitor name is xiao ming
Monitor = &b
fmt.Printf("Monitor name is %s\n", *Monitor) // Monitor name is xiao hong
}
因为Monitor指向的是一个地址变量,也就是b的地址,而不是b的副本,所以当我们修改b变量的时候,同样的也会连带修改Monitor。
var Monitor *string
b := "xiao hong"
Monitor = &b
b = "big hong"
fmt.Printf("Monitor name is %s\n", *Monitor) // Monitor name is big hong
又或者说对Monitor的解引用进行修改,也是可以更改到b的值
var Monitor *string
b := "xiao hong"
Monitor = &b
*Monitor = "xiao liu"
fmt.Printf("Monitor name is %s\n", *Monitor) // Monitor name is xiao liu
fmt.Printf("b is %s\n", b) // b is xiao liu
注意事项⚠️
通过把一个指针变量的解引用赋值给其他变量的时候,他是克隆副本来完成的,而不是通过指针地址!
指针的接受者
我们知道指针同样也可以作为一个形参来进行传递,那么我们就可以通过指针的形式,来修改函数的外部变量了。
func change(a *int) {
*a = 3232
}
func main() {
a := 123
change(&a)
fmt.Println(a) // 3232
}
或者说还有另一种方式也可以达到同样的效果
type obj struct {
num int
name string
}
func (a *obj) change() {
a.num += 1
}
func main() {
test := obj{11, "haha"}
test.change()
fmt.Printf("this is obj %+v",test)
// this is obj {num:12 name:haha}
}
总之,在Go里面,指针的使用非常的灵活,但是还是要合理的使用,而不能过度的去使用指针。
总结
总结起来,在Go中的指针可以总结为以下几点:
- 指针是存储的内存地址
- 操作符& 提供的是变量的内存地址
- 操作符* 提供的是指针所只想的值
- 使用指针可以跨越函数方法进行修改
- 指针可以联通结构一起使用
- 应该合理的使用指针
最后,其实映射和切片也是使用的指针,只不过它们都是隐式的使用。
最后的最后