Golang 中直接赋值,是值传递还是地址传递?

1. 普通变量

普通变量都是值传递,通过新开辟一篇内存并让引用指向这片内存

	a := 1
	b := a
	fmt.Printf("%p\n%p", &a, &b)
	// 0xc0000160a8
	// 0xc0000160c0
	a := 1.0
	b := a
	fmt.Printf("%p\n%p", &a, &b)
	// 0xc0000160a8
	// 0xc0000160c0
	a := "hello"
	b := a
	fmt.Printf("%p\n%p", &a, &b)
	// 0xc0000160a8
	// 0xc0000160c0

其他基本类型也是相同…

2. array

数组赋值时地址不同,创建了一个新的副本,同样是值传递

	a := [2]int{1, 2, 3}
	b := a
	fmt.Printf("%p\n%p", &a, &b)
	// 0xc0000160a8
	// 0xc0000160c0

3. slice

新的切片改动会对原来的造成影响

	a := []int{}
	b := a
	fmt.Printf("%p\n%p\n", &a, &b)
	// 0xc000004078
	// 0xc000004090

注意:切片赋值底层指向的是同一个数组,只有通过 append 进行增加元素时发生了扩容,切片才会指向新的数组

4. map

新的 map 中的元素实际地址与原来相同,说明会对原来的map造成影响

	a := map[int]string{1: "hi"}
	b := a
	fmt.Printf("%p\n%p\n", &a, &b)
	a[1] = "go"
	fmt.Printf("%s\n%s\n", a[1], b[1])
	// 0xc000006028
	// 0xc000006030
	// go
	// go

5. 结构体

结构体是值传递,其中普通的字段重新创建一个副本,指针字段还指向原来的地址(解释了 slice 和 map ,slice 和 map 底层就是有一个指针分别指向一个普通数组和一个bucket数组的结构)

	a := []Student{{1}, {2}}
	b := a
	fmt.Printf("%p\n%p\n", &a, &b)
	// 0xc000004078
	// 0xc000004090

6. 总结

  • array 、结构体可以通过直接赋值并对新的结构体操作,不会产生安全问题
  • slice,map 不推荐直接赋值
    • slice 可以通过 copy 函数进行复制
    • map 可以通过遍历来复制
  • 实际上 go 使用的都是值传递,也就是复制一份新的副本,slice 和 map 特殊在它们本身就是一种结构体,这个结构体内部包含了一个指向实际数据的索引,在他们进行副本拷贝时这个索引还是指向原来的位置,所以拷贝后的影响还是能在原来的 slice 或 map 看到

其实 go 中赋值的过程与他们作为参数传递的过程都是一样的都是值传递(包括结构体),slice 和 map 的底层也是结构体。

你可能感兴趣的:(golang,golang)