数组的值传递

  1. func main() {
  2. arrayA := [2]int{100, 200}
  3. var arrayB [2]int
  4. arrayB = arrayA
  5. fmt.Printf("arrayA : %p , %v\n", &arrayA, arrayA)
  6. fmt.Printf("arrayB : %p , %v\n", &arrayB, arrayB)
  7. testArray(arrayA)
  8. }
  9. func testArray(x [2]int) {
  10. fmt.Printf("func Array : %p , %v\n", &x, x)
  11. }
  12. // arrayA : 0xc4200bebf0 , [100 200]
  13. // arrayB : 0xc4200bec00 , [100 200]
  14. // func Array : 0xc4200bec30 , [100 200]

go的数组是值类型,赋值和函数参数传递都会复制整个数组。可以看到,三个内存地址都不同,这也就验证了 Go 中数组赋值和函数传参都是值复制的。那这会导致什么问题呢? 每次传参都用数组,假设数组的元素大小有100w, 在64位的机器上就需要花费800w字节,8MB的内存,开销大得惊人。所以我们一般使用指针传递:

  1. func main() {
  2. arrayA := [2]int{100, 200}
  3. testArrayPoint1(&arrayA) // 1.传数组指针
  4. arrayB := arrayA[:]
  5. testArrayPoint2(&arrayB) // 2.传切片
  6. fmt.Printf("arrayA : %p , %v\n", &arrayA, arrayA)
  7. }
  8. func testArrayPoint1(x *[2]int) {
  9. fmt.Printf("func Array : %p , %v\n", x, *x)
  10. (*x)[1] += 100
  11. }
  12. func testArrayPoint2(x *[]int) {
  13. fmt.Printf("func Array : %p , %v\n", x, *x)
  14. (*x)[1] += 100
  15. }
  16. // func Array : 0xc4200b0140 , [100 200]
  17. // func Array : 0xc4200b0180 , [100 300]
  18. // arrayA : 0xc4200b0140 , [100 400]

记住,在golang中,区别一个变量是数组还是切片,就看有没有定义长度

  1. array := []int{10, 20, 30, 40}
  2. fmt.Printf("%p\n %v\n", &array, array)
  3. copy(array, array[1:])
  4. fmt.Printf("%p\n %v\n", &array, array)
  5. 0xc000258e00
  6. [10 20 30 40]
  7. 0xc000258e00
  8. [20 30 40 40]

参考

深入解析 Go 中 Slice 底层实现
Go数组和切片你不知道的区别