什么是引用类型
简单类说就是不同的变量内存地址是一样的,也就是说同一个内存地址有不同的别名。
code-11
2
3
4
5
6
7 dd = dict()
c = dd
id(c)
4476836672
id(dd)
4476836672
>>>
code-1
中的 Python 代码显示 c 和 dd 两个变量的内存地址都是一样的。
Immutable type 不是引用类型
Int,string,bool 这些 immutable 类型不会有引用类型
1 | package main |
变量 a 赋值给 d ,d 和 a 的地址不同,字符串 s 二次赋值之后地址没有改变,在 immutable type 中不存在两个变量内存地址是一样的。
Map 可以在函数内部改变,但是 map 不是引用类型
Go 中函数传参是按值传递,在函数内部无法改变函数外部的值,但是 map 可以,是不是 map 是引用类型。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28package main
import (
"fmt"
)
func main() {
var m map[int]string = map[int]string{
0: "0",
1: "1",
}
mm := m
fmt.Printf("%p\n", &m) //0xc42002a028
fmt.Printf("%p\n", &mm) //0xc42002a030
fmt.Println(m) // map[0:0 1:1]
fmt.Println(mm) //map[1:1 0:0]
changeMap(m)
fmt.Printf("%p\n", &m) //0xc42002a028
fmt.Printf("%p\n", &mm)//0xc42002a030
fmt.Println(m) //map[2:2 0:0 1:1]
fmt.Println(mm) //map[0:0 1:1 2:2]
}
func changeMap(mmm map[int]string) {
mmm[2] = "2"
fmt.Printf("changeMap func %p\n", mmm) //changeMap func 0xc420014150
}
可以明确看到 main 中的 mm 和 m 地址完全不同,调用函数 changeMap 之后,它们的值都发生了改变,在函数 changeMap 内部,参数 mmm 的地址和 m 以及 mm 都不同,证实 map 并不是引用传参。
再一个例子。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16package main
import (
"fmt"
)
func main() {
var m map[int]string
makeMap(m)
fmt.Println(m == nil) //true
}
func makeMap(m map[int]string) {
m = make(map[int]string)
}
如果是引用传参 main 函数中的输出不应该是 true。
Channel 也是按值传参
1 | package main |
例子中的 channel 在函数内发生了值传递,但是函数内部和外部的 channel 地址不同。
Map 不是引用类型,为什么可以在函数内部改变
Go 源代码中显示 https://golang.org/src/runtime/hashmap.go map 底层是一个指向 hmap 的指针,这就可以解释即使函数传参是按值传递,由于传递的是指针的拷贝,指针指向的底层 hmap 并没有改变,所以可以在函数内部改变 map 。
Go 中没有引用类型