Golang 中直接赋值,是值传递还是地址传递?
1. 普通变量
普通变量都是值传递,通过新开辟一篇内存并让引用指向这片内存
a := 1
b := a
fmt.Printf("%p
%p", &a, &b)
// 0xc0000160a8
// 0xc0000160c0
a := 1.0
b := a
fmt.Printf("%p
%p", &a, &b)
// 0xc0000160a8
// 0xc0000160c0
a := "hello"
b := a
fmt.Printf("%p
%p", &a, &b)
// 0xc0000160a8
// 0xc0000160c0
其他基本类型也是相同…
2. array
数组赋值时地址不同,创建了一个新的副本,同样是值传递
a := [2]int{
1, 2, 3}
b := a
fmt.Printf("%p
%p", &a, &b)
// 0xc0000160a8
// 0xc0000160c0
3. slice
新的切片改动会对原来的造成影响
a := []int{
}
b := a
fmt.Printf("%p
%p
", &a, &b)
// 0xc000004078
// 0xc000004090
注意:切片赋值底层指向的是同一个数组,只有通过 append 进行增加元素时发生了扩容,切片才会指向新的数组
4. map
新的 map 中的元素实际地址与原来相同,说明会对原来的map造成影响
a := map[int]string{
1: "hi"}
b := a
fmt.Printf("%p
%p
", &a, &b)
a[1] = "go"
fmt.Printf("%s
%s
", a[1], b[1])
// 0xc000006028
// 0xc000006030
// go
// go
5. 结构体
结构体是值传递,其中普通的字段重新创建一个副本,指针字段还指向原来的地址(解释了 slice 和 map ,slice 和 map 底层就是有一个指针分别指向一个普通数组和一个bucket数组的结构)
a := []Student{
{
1}, {
2}}
b := a
fmt.Printf("%p
%p
", &a, &b)
// 0xc000004078
// 0xc000004090
6. 总结
-
array 、结构体可以通过直接赋值并对新的结构体操作,不会产生安全问题 slice,map 不推荐直接赋值 slice 可以通过 copy 函数进行复制 map 可以通过遍历来复制 实际上 go 使用的都是值传递,也就是复制一份新的副本,slice 和 map 特殊在它们本身就是一种结构体,这个结构体内部包含了一个指向实际数据的索引,在他们进行副本拷贝时这个索引还是指向原来的位置,所以拷贝后的影响还是能在原来的 slice 或 map 看到
其实 go 中赋值的过程与他们作为参数传递的过程都是一样的都是值传递(包括结构体),slice 和 map 的底层也是结构体。
