当前位置:   article > 正文

GO语言-Slice切片_golang slice 三参数

golang slice 三参数

前言

切片Slice,与数组相似。也叫变长数组或者动态数组。特点:变长。

Slice是一个引用类型的容器,指向了一个底层数组。

创建slice语法

常规操作

  1. var slice_name []type
  2. slice_name := []type{v1, v2, v3, v4}

在已有数组上创建切片

  1. //切片名 := 数组[开始下标, 结束下标] 注意:不包含结束下标
  2. slice_name := array_name[start:end]
  1. func main() {
  2. arr := [9]int{1, 2, 3, 4, 5, 6, 7, 8, 9}
  3. slice_test1 := arr[1:4] //2-4
  4. slice_test2 := arr[:5] //1-5
  5. slice_test3 := arr[5:] //6-9
  6. slice_test4 := arr[:] //1-9
  7. fmt.Println(slice_test1)
  8. fmt.Println(slice_test2)
  9. fmt.Println(slice_test3)
  10. fmt.Println(slice_test4)
  11. }

make关键字创建slice

make关键字专门用于创建引用类型的数据。

语法

make(type, size1, size2)

第一个参数是类型 slice、map、chan

第二个参数是长度

第三个参数是容量。

存储长度超过容量时,会自动扩容。

默认存储数据,int类型时使用0填充;string类型时使用空字符串填充。可以通过下标操作默认已存在的值。

  1. func main() {
  2. slice_test1 := make([]int, 3, 5)
  3. fmt.Printf("slice_test1: %v; slice长度: %v; slice容量: %v\n", slice_test1, len(slice_test1), cap(slice_test1))
  4. //append元素,超过slice容量
  5. slice_test1 = append(slice_test1, 1, 2, 3)
  6. fmt.Println("---append后---")
  7. fmt.Printf("slice_test1: %v; slice长度: %v; slice容量: %v\n", slice_test1, len(slice_test1), cap(slice_test1))
  8. }

slice赋值操作对底层数组的影响

  1. 对array元素操作时,所有指向array的slice的元素也会发生改变。
  2. 对slice中元素操作时,实际时对array的元素进行操作。
  3. slice发生扩容时,实际是开辟了新的内存空间,所以原来的array不会发生改变。

具体示例 

1.当底层数组改变时,所有指向这个array的slice响应索引位置上的值也会发生改变。

  1. func main() {
  2. arr := [6]int{1, 2, 3, 4, 5, 6}
  3. slice_test1 := arr[:]
  4. slice_test2 := arr[:3]
  5. slice_test3 := arr[3:]
  6. fmt.Println("slice_test1:", slice_test1)
  7. fmt.Println("slice_test2:", slice_test2)
  8. fmt.Println("slice_test3:", slice_test3)
  9. arr[1] += 1
  10. arr[4] += 1
  11. fmt.Println("---对array元素操作后---")
  12. fmt.Println("slice_test1:", slice_test1)
  13. fmt.Println("slice_test2:", slice_test2)
  14. fmt.Println("slice_test3:", slice_test3)
  15. }

 

2.当操作slice内容时,比如从slice[index]修改索引位置上的值或者使用append新增值时,都是对底层数组进行操作。所以同(1),其他指向这个array的slice对应的位置也会发生改变。

  1. func main() {
  2. arr := [6]int{1, 2, 3, 4, 5, 6}
  3. slice_test1 := arr[:]
  4. slice_test2 := arr[:3]
  5. slice_test3 := arr[3:]
  6. fmt.Println("slice_test1:", slice_test1)
  7. fmt.Println("slice_test2:", slice_test2)
  8. fmt.Println("slice_test3:", slice_test3)
  9. slice_test1[1] += 1
  10. slice_test1[4] += 1
  11. fmt.Println("---对slice元素操作后---")
  12. fmt.Println("slice_test1:", slice_test1)
  13. fmt.Println("slice_test2:", slice_test2)
  14. fmt.Println("slice_test3:", slice_test3)
  15. }

3.当使用append给slice增加值,操作slice容量,slice发生扩容。slice扩容时,会开辟新的内存地址。将原有的array内的值复制过来;进行扩容后再加入新的值。所以扩容情况下所新增的值不会对原有的array进行操作。

所以slice发生扩容时,只有被扩容的slice内的值发生变化。array不会发生变化,其他指向原有array的slice中的值也不会发生变化。

  1. func main() {
  2. arr := [6]int{1, 2, 3, 4, 5, 6}
  3. slice_test1 := arr[:]
  4. slice_test2 := arr[:3]
  5. slice_test3 := arr[3:]
  6. fmt.Printf("slice_test1: %v; slice_test1长度: %v; slice_test1容量: %v \n", slice_test1, len(slice_test1), cap(slice_test1))
  7. fmt.Println("slice_test2:", slice_test2)
  8. fmt.Println("slice_test3:", slice_test3)
  9. slice_test1 = append(slice_test1, 7, 8, 9)
  10. slice_test1[1] += 1
  11. slice_test1[4] += 1
  12. fmt.Println("---slice_test1发生扩容时---")
  13. fmt.Println("原数组arr:", arr)
  14. fmt.Println("slice_test1:", slice_test1)
  15. fmt.Println("slice_test2:", slice_test2)
  16. fmt.Println("slice_test3:", slice_test3)
  17. }

append插入元素

语法

  1. slice_name = append(slice_name, v1, v2)
  2. slice_name = append(slice_name, slicename2...)

 可以把slice_name2切片的值全部插入slice_name中。但是slice_name2后面必须有三个点,表示时切片。

  1. func main() {
  2. slice_test1 := []int{1, 2, 3}
  3. slice_test2 := []int{4, 5, 6}
  4. fmt.Println("append前slice_test1:", slice_test1)
  5. slice_test1 = append(slice_test1, slice_test2...)
  6. fmt.Println("appendslice_test2后slice_test1:", slice_test1)
  7. slice_test1 = append(slice_test1, 7, 8, 9)
  8. fmt.Println("append单个元素后slice_test1:", slice_test1)
  9. }

浅拷贝: slice1 := slice2

深拷贝: slice1 := append([]int{}, slice2...)

切片Slice内存分析

  查看内存地址的时候。数值类型,如array、int等,fmt.Printf(%p\n, &arr) ,要再变量前加上&符号;引用类型,如slice,fmt.Printf(%p\n, slice1) ,不需要加&符号。

  1. func main() {
  2. s1 := []int{1, 2, 3, 4}
  3. fmt.Println(s1)
  4. fmt.Printf("s1的地址: %p; s1的长度: %v; s1的容量: %v \n", s1, len(s1), cap(s1))
  5. s1 = append(s1, 5, 6)
  6. fmt.Println(s1)
  7. fmt.Printf("s1的地址: %p; s1的长度: %v; s1的容量: %v \n", s1, len(s1), cap(s1))
  8. }

1.创建数组s1时,是先创建一个底层数组。然后再用切片s1指向底层数组。此时长度和容量一样。

2.切片本身不存储数据,都是底层数组存储数据。所以修改也是修改底层数组。

3.扩容:底层数组扩容时,其容量都是成倍扩容的。所以使用append操作切片,发生扩容时,slice的容量也是成倍扩容。

4.因为扩容要改变底层数组,所以底层数组的内存地址发生了改变;如果不需要扩容,内存地址就不会发生改变。 

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/从前慢现在也慢/article/detail/206456
推荐阅读
相关标签
  

闽ICP备14008679号