• 【go语言学习】切片slice


    go语言中数组的长度是固定的并且数组长度属于类型的一部分,所以数组有很多的局限性。
    go提供了一种更加灵活强悍的内置类型切片(“动态数组”)。
    切片(Slice)是一个拥有相同类型元素的可变长度的序列。它是基于数组类型做的一层封装。它非常灵活,支持自动扩容。
    切片是一个引用类型,它的内部结构包含地址长度容量

    一、切片的声明和初始化

    1、直接声明切片

    var name []T
    其中:name-切片的名称
               T-切片的类型

    package main
    
    import (
    	"fmt"
    )
    
    func main() {
    	var numSlice = []int{1, 3, 5, 7, 9}
    	fmt.Println(numSlice)
    	var stringSlice []string
    	stringSlice = []string{"北京", "上海", "深圳", "苏州"}
    	fmt.Println(stringSlice)
    }
    

    运行结果

    [1 3 5 7 9]
    [北京 上海 深圳 苏州]
    
    2、基于数组创建切片

    var slice = arr[low: high]
    其中:表达式中的low和high表示一个索引范围(左包含,右不包含)

    package main
    
    import (
    	"fmt"
    )
    
    func main() {
    	var numArry = [5]int{1, 2, 3, 4, 5}
    	var numSlice = numArry[2:4]
    	fmt.Println(numSlice)
    }
    

    运行结果

    [3 4]
    
    3、使用make()函数构造切片

    var slice = make([]T, len, cap)
    其中:T-切片的元素类型
               len-切片的长度
               cap-切片的容量

    package main
    
    import (
    	"fmt"
    )
    
    func main() {
    	var intSlice = make([]int, 2, 4)
    	fmt.Println(intSlice)
    	fmt.Println(len(intSlice))
    	fmt.Println(cap(intSlice))
    }
    

    运行结果

    [0 0]
    2
    4
    

    二、切片的本质

    切片的本质就是对底层数组的封装,它包含了三个信息:底层数组的指针、切片的长度(len)和切片的容量(cap)
    举例:
    数组 a := [8]int{0, 1, 2, 3, 4, 5, 6, 7},切片s1 := a[0:5],相应示意图如下:

    切片s2 := a[3:6],相应示意图如下:

    对slice所做的任何修改都将反映在底层数组中。
    当多个切片共享相同的底层数组时,每个切片对元素所做的更改将在数组中反映出来。

    package main
    
    import (
    	"fmt"
    )
    
    func main() {
    	arr := [8]int{0, 1, 2, 3, 4, 5, 6, 7}
    	fmt.Println("操作前:", arr)
    	slice := arr[:5]
    	fmt.Println("操作前:", slice)
    	slice[0] = 100
    	fmt.Println("操作后:", arr)
    	fmt.Println("操作后:", slice)
    }
    

    运行结果

    操作前: [0 1 2 3 4 5 6 7]
    操作前: [0 1 2 3 4]
    操作后: [100 1 2 3 4 5 6 7]
    操作后: [100 1 2 3 4]
    

    三、切片的操作

    1、切片的遍历

    切片的遍历方式和数组是一致的,支持索引遍历和for range遍历。

    package main
    
    import (
    	"fmt"
    )
    
    func main() {
    	slice := []int{0, 1, 2, 3, 4, 5, 6, 7}
    	for i := 0; i < len(slice); i++ {
    		fmt.Printf("[%v-%v]	", i, slice[i])
    	}
    	fmt.Println("")
    	for k, v := range slice {
    		fmt.Printf("[%v-%v]	", k, v)
    	}
    }
    

    运行结果

    [0-0]   [1-1]   [2-2]   [3-3]   [4-4]   [5-5]   [6-6]   [7-7]   
    [0-0]   [1-1]   [2-2]   [3-3]   [4-4]   [5-5]   [6-6]   [7-7]
    
    2、切片的复制拷贝
    • 直接赋值拷贝,浅拷贝
      拷贝前后两个变量共享底层数组,对一个切片的修改会影响另一个切片的内容
    package main
    
    import (
    	"fmt"
    )
    
    func main() {
    	slice1 := []int{0, 1, 2, 3, 4, 5, 6, 7}
    	slice2 := slice1
    	slice2[0] = 100
    	fmt.Println("slice1:", slice1)
    	fmt.Println("slice2:", slice2)
    }
    

    运行结果

    slice1: [100 1 2 3 4 5 6 7]
    slice2: [100 1 2 3 4 5 6 7]
    
    • 使用copy()函数操作,深拷贝

    copy(destSlice, srcSlice)
    其中:destSlice-目标切片
               srcSlice-源切片

    package main
    
    import (
    	"fmt"
    )
    
    func main() {
    	slice1 := []int{0, 1, 2, 3, 4, 5, 6, 7}
    	slice2 := make([]int, 5, 5)
    	copy(slice2, slice1)
    	fmt.Println("slice2:", slice2)
    	slice2[0] = 100
    	fmt.Println("slice1:", slice1)
    	fmt.Println("slice2:", slice2)
    }
    

    运行结果

    slice2: [0 1 2 3 4]
    slice1: [0 1 2 3 4 5 6 7]
    slice2: [100 1 2 3 4]
    
    3、向切片中添加元素append

    Go语言的内建函数append()可以为切片动态添加元素。 可以一次添加一个元素,可以添加多个元素,也可以添加另一个切片中的元素(后面加…)

    slice = append(slice, num1, num2)
    slice = append(slice, slice...)

    • append函数会改变slice所引用的数组的内容,从而影响到引用同一数组的其它slice。
    • 但当slice中没有剩余空间(即(cap-len) == 0)时,切片就会自动按照一定的策略进行“扩容”,此时将动态分配新的数组空间。返回的slice数组指针将指向这个空间,而原数组的内容将保持不变;其它引用此数组的slice则不受影响。
    package main
    
    import (
    	"fmt"
    )
    
    func main() {
    	arr := [5]int{0, 1, 2, 3, 4}
    	slice := arr[:3]
    	slice = append(slice, 100)
    	fmt.Println("arr:", arr)
    	fmt.Println("slice:", slice)
    	fmt.Println("------------------")
    	slice = append(slice, 200)
    	fmt.Println("arr:", arr)
    	fmt.Println("slice:", slice)
    	fmt.Println("------------------")
    	slice = append(slice, 300)
    	fmt.Println("arr:", arr)
    	fmt.Println("slice:", slice)
    }
    

    运行结果

    arr: [0 1 2 100 4]
    slice: [0 1 2 100]
    ------------------
    arr: [0 1 2 100 200]
    slice: [0 1 2 100 200]
    ------------------
    arr: [0 1 2 100 200]
    slice: [0 1 2 100 200 300]
    
    4、从切片中删除元素

    Go语言中并没有删除切片元素的专用方法,我们可以使用切片本身的特性来删除元素。

    slice = append(slice[:index], slice[index+1:]...)

    package main
    
    import "fmt"
    
    func main() {
    	slice := []int{1, 2, 3, 4, 5}
    	slice = append(slice[:3], slice[4:]...)
    	fmt.Println(slice)
    }
    

    运行结果

    [1 2 3 5]
    
    5、注意事项
    • 切片不能进行比较,切片唯一合法的比较操作是和nil比较。
    • 判断切片是否是空的,要使用len(slice) == 0来判断,不应该使用slice == nil来判断
    package main
    
    import "fmt"
    
    func main() {
    	var s1 []int
    	s2 := []int{}
    	s3 := make([]int, 0, 0)
    	fmt.Printf("s1: len = %v, cap = %v, isNil:%v
    ", len(s1), cap(s1), s1 == nil)
    	fmt.Printf("s2: len = %v, cap = %v, isNil:%v
    ", len(s2), cap(s2), s2 == nil)
    	fmt.Printf("s3: len = %v, cap = %v, isNil:%v
    ", len(s3), cap(s3), s3 == nil)
    }
    

    运行结果

    s1: len = 0, cap = 0, isNil:true
    s2: len = 0, cap = 0, isNil:false
    s3: len = 0, cap = 0, isNil:false
    
  • 相关阅读:
    博客园转文章的方法
    http协议相关面试题
    接口测试基础01
    文件上传下载
    括号-回溯
    幂集-回溯
    分割数组为连续子序列- -贪心法
    不使用临时变量交换数字
    计数质数
    拼接最大值
  • 原文地址:https://www.cnblogs.com/everydawn/p/13886613.html
Copyright © 2020-2023  润新知