当前位置:   article > 正文

Golang:切片的声明、初始化以及操作示例,详解、概括_golang 切片初始化

golang 切片初始化

Golang基础学习项目地址:https://github.com/LeoLeeWithWarmPants/golangStudyhttps://github.com/LeoLeeWithWarmPants/golangStudy

概述

slice本质上是一个数据结构(struct结构体)。

  • 切片是数组的一个引用,即切片的底层是一个数组,所以切片是一个引用类型。

  • 切片的长度是可以变化,由于其支持扩容(类似于Java的List),可以理解切片为一个“长度动态变化的数组”。

    • 需要注意的是,支持扩容并不代表可以越界操作

    • 扩容后,底层创建并引用了新的数组,将数据赋值到新的数组

  • 可以使用数组或者是make两种方式来初始化一个切片。

    • 需要注意的时make也是会创建底层数组的。数组的长度为make设置的capcity,数组元素的值为数组类型对应的默认值。

  • 切片可以被继续切片。产生的新切片和原切片公用同一个底层数组,修改新的切片会影响原切片

slice变量声明、初始化后,其内存空间内包含:

  • slice首个元素的地址(该元素对应原始数组的某个元素)

  • slice的长度

  • 容量(slice底层数组的长度)

在使用数组初始化切片的时候,一定要注意数组是值传递,还是作为了切片的底层数组通过make创建的切片顶层的数组只能通过切片来操作,该数组没有其他的引用

示例

  1. package main
  2. import (
  3. "errors"
  4. "fmt"
  5. )
  6. const length int = 5
  7. var intArray = [length]int{1, 3, 5, 7, 9}
  8. //从一个数组中获取一个切片
  9. //通过make创建的切片顶层的数组只能通过切片来操作,该数组没有其他的引用
  10. func getSliceFromArray(array [length]int) []int {
  11. slice := array[1:3] // 1:3 代表从数组下标为1的元素开始取值,到下标为3的元素位置,不包含3。如果从0开始引用数组,也可以省略冒号前的0(如 array[:3]),反之同理。
  12. return slice
  13. }
  14. //通过make创建一个切片
  15. func getSliceByMake() []int {
  16. var slice3 []int = make([]int, 4, 8)
  17. fmt.Printf("slice3 length=%d, capcity=%d\n", len(slice3), cap(slice3))
  18. return slice3
  19. }
  20. //创建切片时,初始化切片引用的数组
  21. func getSliceByInitArray() []int {
  22. var slice4 []int = []int{1, 3, 5, 7, 9}
  23. fmt.Printf("slice4 length=%d, capcity=%d\n", len(slice4), cap(slice4))
  24. return slice4
  25. }
  26. //对切片进行切片,从一个切片产生一个新的切片
  27. func getSliceFromSlice(slice []int) []int {
  28. return slice[0:2]
  29. }
  30. //切片的遍历
  31. func sliceTraverseByFori(slice []int) {
  32. fmt.Println("sliceTraverseByFori executing...")
  33. for i := 0; i < len(slice); i++ {
  34. if i == len(slice)-1 {
  35. fmt.Printf("slice[%d]:%d \n", i, slice[i])
  36. } else {
  37. fmt.Printf("slice[%d]:%d ", i, slice[i])
  38. }
  39. }
  40. slice[0] = 2
  41. }
  42. func sliceTraverseByForRange(slice []int) {
  43. fmt.Println("sliceTraverseByForRange executing...")
  44. for idx, element := range slice {
  45. if idx == len(slice)-1 {
  46. fmt.Printf("slice[%d]:%d \n", idx, element)
  47. } else {
  48. fmt.Printf("slice[%d]:%d ", idx, element)
  49. }
  50. }
  51. }
  52. //测试切片扩容
  53. func testDilatationByAppend(slice1 []int, slice2 []int, args ...int) []int {
  54. if slice1 == nil {
  55. panic(errors.New("被扩容的切片不能为空"))
  56. }
  57. if slice2 != nil {
  58. slice1 = append(slice1, slice2...)
  59. }
  60. if args != nil && len(args) > 0 {
  61. slice1 = append(slice1, args...)
  62. }
  63. return slice1
  64. }
  65. func main() {
  66. //从一个数组中获取一个切片
  67. slice1 := getSliceFromArray(intArray)
  68. fmt.Printf("slice1 from an array, slice1=%v,length=%d,capacity=%d\n", slice1, len(slice1), cap(slice1))
  69. fmt.Printf("intArray memory address:%p\n", &intArray)
  70. fmt.Printf("intArray[1] memory address:%p\n", &intArray[1])
  71. fmt.Printf("slice1 memory address:%p\n", &slice1)
  72. fmt.Printf("slice1[0]=%d, slice1[0] memory address:%p\n", slice1[0], &slice1[0]) // slice1[0] == intArray[1] == 3
  73. //由于getSliceFromArray函数中声明并初始化了slice1,intArray是基本类型,通过值传递进入了getSliceFromArray函数,所以修改slice1的值并不影响intArray
  74. slice1[0] = 2
  75. fmt.Printf("after slice1 changed,slice1=%v\n", slice1)
  76. fmt.Printf("after slice1 changed,intArray=%v\n", intArray)
  77. //当slice2和intArray2处在同一作用域时,slice2中的元素地址指向了intArray2中的元素,修改slice2的元素值等于修改intArray2中的元素
  78. intArray2 := [length]int{0, 2, 4, 6, 8}
  79. slice2 := intArray2[1:3]
  80. fmt.Printf("slice2=%v\n", slice2)
  81. slice2[0] = 28
  82. fmt.Printf("after slice2 changed,slice2=%v\n", slice2)
  83. fmt.Printf("after slice2 changed,intArray2=%v\n", intArray2)
  84. //通过make创建切片
  85. slice3 := getSliceByMake()
  86. fmt.Printf("slice3:%v, slice3 memory address:%p\n", slice3, &slice3)
  87. //创建切片时,初始化切片引用的数组
  88. slice4 := getSliceByInitArray()
  89. fmt.Printf("slice4=%v\n", slice4)
  90. //切片fori遍历
  91. sliceTraverseByFori(slice4)
  92. sliceTraverseByFori(slice4) //由于切片是引用传递,所以方法内部对切片的变动,将会影响源数据
  93. sliceTraverseByForRange(slice4)
  94. //对切片进行切片,从一个切片产生一个新的切片
  95. fmt.Printf("slice4=%v\n", slice4)
  96. slice5 := getSliceFromSlice(slice4)
  97. fmt.Printf("slice5=%v\n", slice5)
  98. slice5[0] = 33
  99. fmt.Printf("after slice5 changed, slice4=%v\n", slice4) //说明切片slice4产生的切片slice5,slice4和slice5公用一个底层的数组
  100. //切片扩容测试
  101. intArray3 := [...]int{1, 2}
  102. slice6 := intArray3[:]
  103. fmt.Printf("slice6=%v, length=%d, capcity=%d, address=%p\n", slice6, len(slice6), cap(slice6), &slice6)
  104. slice7 := []int{3, 4, 5}
  105. slice6 = testDilatationByAppend(slice6, slice7)
  106. //由此可以看到切片在append元素之后,capcity增加了,虽然切片的地址没有变化,但是由数组声明后长度不可变可知,底层的数据肯定不是intArray3了
  107. fmt.Printf("slice6=%v, length=%d, capcity=%d, address=%p\n", slice6, len(slice6), cap(slice6), &slice6)
  108. //切片的拷贝
  109. slice8 := []int{1, 2, 3}
  110. slice9 := make([]int, 6)
  111. copyLength := copy(slice9, slice8)
  112. fmt.Printf("copyLength=%d\n", copyLength)
  113. fmt.Printf("slice8=%v\n", slice8)
  114. fmt.Printf("slice9=%v\n", slice9)
  115. }

声明:本文内容由网友自发贡献,转载请注明出处:【wpsshop】
推荐阅读
相关标签
  

闽ICP备14008679号