Go中指针的二三事 | Go 主题月

319 阅读4分钟

前言

WechatIMG52.jpeg 今天是个好日子,适合来一篇文章庆祝一下,那么我要来点什么呢,想了一圈,不如就来聊一下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类型的指针的时候,就会报错。

注意⚠️

我们可以看到在指针中的*,它存在这两种作用,一个是声明一个指针的类型,一个是对指针的变量进行一个解引用,而它们使用上的区别就是,一个是放置在类型前面,一个是防止在变量的前面。

指针的作用就是指向

1197823-20190219110411196-752282810.jpeg

从图片中,我们可以看出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中的指针可以总结为以下几点:

  1. 指针是存储的内存地址
  2. 操作符& 提供的是变量的内存地址
  3. 操作符* 提供的是指针所只想的值
  4. 使用指针可以跨越函数方法进行修改
  5. 指针可以联通结构一起使用
  6. 应该合理的使用指针

最后,其实映射和切片也是使用的指针,只不过它们都是隐式的使用。

最后的最后

下载.jpeg