数组与slice区别

数组是固定长度的,不同长度的数组不是相同类型,初始化方式如下

  1. t := [3]int{}

slice长度可变,实际上是一个指向相应底层对象的指针,初始化方式如下

  1. t := make([]int, 0)
  2. or
  3. t := []int{}

对任意数组或slice切片得到的是slice,实际上是一个包含了长度和容量的指针,指向了其底层位置

  1. func main() {
  2. t := [3]int{1,2,3}
  3. v := t[:]
  4. fmt.Printf("%v %T %p\n", t, t ,&t)
  5. fmt.Printf("%v %T %p\n", v, v, v)
  6. v[1] = 5
  7. fmt.Printf("%v %T %p\n", t, t, &t)
  8. }
  9. // result
  10. [1 2 3] [3]int 0xc0000ae078
  11. [1 2 3] []int 0xc0000ae078
  12. [1 5 3] [3]int 0xc0000ae078

append

对于append方法,如果其slice所对应的底层数组还有空间,则在原地append,否则会申请新的底层数组空间

  1. func main() {
  2. t := [3]int{1,2,3}
  3. v := t[:2]
  4. fmt.Printf("%v %T %p\n", t, t ,&t)
  5. fmt.Printf("%v %T %p\n", v, v, v)
  6. v = append(v ,5)
  7. fmt.Printf("%v %T %p\n", t, t, &t)
  8. fmt.Printf("%v %T %p\n", v, v, v)
  9. fmt.Println("***************************")
  10. t = [3]int{1,2,3}
  11. v = t[:]
  12. fmt.Printf("%v %T %p\n", t, t ,&t)
  13. fmt.Printf("%v %T %p\n", v, v, v)
  14. v = append(v ,5)
  15. fmt.Printf("%v %T %p\n", t, t, &t)
  16. fmt.Printf("%v %T %p\n", v, v, v)
  17. }
  18. // result
  19. [1 2 3] [3]int 0xc0000ae078
  20. [1 2] []int 0xc0000ae078
  21. [1 2 5] [3]int 0xc0000ae078
  22. [1 2 5] []int 0xc0000ae078
  23. ***************************
  24. [1 2 3] [3]int 0xc0000ae078
  25. [1 2 3] []int 0xc0000ae078
  26. [1 2 3] [3]int 0xc0000ae078
  27. [1 2 3 5] []int 0xc0000c0060

以上是我们所期望多append策略,但并不能保证append一定采用。内置的append采用更复杂的内存扩展策略。因此,通常我们并不知道append调用是否导致了内存的重新分配,因此我们也不能确认新的slice和原始的slice是否引用的是相同的底层数组空间。同样,我们不能确认在原先的slice上的操作是否会影响到新的slice。因此,通常是将append返回的结果直接赋值给输入的slice变量:

  1. runes = append(runes, r)

参数传递

当传参时,数组与slice均是值传递,但slice其实包含3个值,分别是len、cap、和底层指针,所以实际传进去的是底层指针。

  1. package main
  2. import (
  3. "fmt"
  4. )
  5. func printAddressAndChangeValue1(t [3]int) {
  6. fmt.Printf("the address of array t in function when transmit a value is: %p\n", &t)
  7. t[1] = 1
  8. }
  9. func printAddressAndChangeValue2(p []int) {
  10. fmt.Printf("the address of array t in function when transmit a value is: %p\n", p)
  11. p[1] = 1
  12. }
  13. // 验证go数组是值传递还是地址传递
  14. func main() {
  15. t := [3]int{9,8,7}
  16. fmt.Printf("value of t: %v, type of t: %T\n" ,t, t)
  17. fmt.Printf("the address of array t out function is: %p\n", &t)
  18. printAddressAndChangeValue1(t)
  19. fmt.Printf("value of t: %v, type of t: %T\n" ,t, t)
  20. fmt.Println("************************")
  21. p := []int{9,8,7}
  22. fmt.Printf("value of t: %v, type of t: %T\n" ,p, p)
  23. fmt.Printf("the address of array t out function is: %p\n", p)
  24. printAddressAndChangeValue2(p)
  25. fmt.Printf("value of t: %v, type of t: %T\n" ,p, p)
  26. }
  27. // result
  28. value of t: [9 8 7], type of t: [3]int
  29. the address of array t out function is: 0xc000012120
  30. the address of array t in function when transmit a value is: 0xc000012168
  31. value of t: [9 8 7], type of t: [3]int
  32. ************************
  33. value of t: [9 8 7], type of t: []int
  34. the address of array t out function is: 0xc0000121b0
  35. the address of array t in function when transmit a value is: 0xc0000121b0
  36. value of t: [9 1 7], type of t: []int
  37. Process finished with the exit code 0