0%

Go指针特别说明

要区分Go语言和Python的本质区别:

Go语言是变量存的是一片内存地址,修改内容时修改的是内存地址中的内容
而python中是变量只是标签,每次修改,改变的是变量(标签)指向地方,内存中的内容没有变。

  • Python创建一个内容时,是先在内存中开辟相应的空间放内容,然后使用一个变量名(标签)来指向这个地方,所以多个变量之间相互赋值的时候,这些变量都指向了同一块内存空间,通过其中一个变量对内容进行修改则会改动所有的,因为都是指向了一个内容。

  • Go语言是先创建一个变量,根据变量的类型开辟大小的空间,再往内存中放置东西。多变量(必须是同种类型变量)之间相互赋值时,进行的是复制(拷贝)操作,各变量之间是独立的个体,对其中一个修改,是不会影响到其他内容的。所以Go的变量赋值很强调类型。

某个类型的变量只能就收同种类型的数据:

1
2
3
4
5
6
7
8
9
10
11
12
13
arr := [3]int{0,1,2}
bb := arr
fmt.Printf("arr address: %p\n",&arr)
fmt.Printf("bb address: %p\n",&bb)

fmt.Printf("bb: %d\n",bb)
arr[0] = 99
fmt.Printf("bb: %d\n",bb)
// 结果
arr address: 0xc000018240
bb address: 0xc000018260
bb: [0 1 2]
bb: [0 1 2]

解释:通过打印两个变量的内存地址可以发现,地址是不同的,所以Golang中的变量相互赋值实际上拷贝操作,所以修改其中一个列表的值,也不会影响另外一个列表。

Slice 等映射类型除外。 (Slice及以下内容参考下篇 Go基础之内建容器)

Go语言的所有方法一旦有返回值的都是重新创建了新的内容,需要使用新的变量去接收。如

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
arr := make([]int, 2, 16)
b := append(arr, 9) // 这里实际上是先创建了一个len为2,cap为16的[]int类型的变量并开辟了内存空间,然后接收了append函数返回的内容,arr和b不是指向的同一个内容,但是由于arr为slice类型,对arr现有内容的改变影响到b
fmt.Printf("arr address: %p\n",&arr)
fmt.Printf("bb address: %p\n",&bb)

fmt.Printf("bb: %d\n",bb)
arr[1] = 3
fmt.Printf("arr: %d\n",arr)

fmt.Printf("bb: %d\n",bb)
// 结果
arr address: 0xc00009c0c0
bb address: 0xc00009c0e0
bb: [0 0 9]
arr: [0 3]
bb: [0 3 9]

为了能够修改原值,定义函数的时候使用指针,这样一来,通过指针,修改了原先内存中的值。

使用数组指针作为函数形参的时候,函数内使用该指针变量的时候不需要使用,只需要正常数组的使用方式即可,由于Go的语法糖,会自动转化为(数组)。但是Slice不行,如下:

1
2
3
func Push(s *[]int,v int){
*s = append(*s,v)
}
1
2
3
4
func Push(s *[]int, v int) int{
*s = append(*s, v)
return (*s)[len(*s)-1] // 必须使用(*s)[]的形式进行调用
}

总之要转换思想,Python中修改变量的值可以通过其他变量间接修改,因为Python的变量只是标签,但是Go中变量是分配了内存的,想修改,只能通过修改自身的值。