GO切片

切片(Slice)是一个拥有相同类型元素的可变长度的序列。它是基于数组类型做的一层封装。它非常灵活,支持自动扩容。
切片是一个引用类型(直接引用的内存地址),它的内部结构包含地址、长度和容量。切片一般用于快速地操作一块数据集合。
切片是引用类型,不支持直接比较,只能和nil比较!

得到切片的三种方式:

  • 直接声明a := []int{1,2,3} len:3 cap:3
  • 基于数组得到切片 m := [5]int b:= m[:3] len:3, cap:5,数组发生改变,切片随即发生改变,反之亦然
  • 基于切片得到切片 b := a[:2] len:2 cap:3

切片定义

基本语法:var name []T
name:变量名
T:切片中元素类型
切片定义

//基本声明:直接定义
    var a []int     //声明一个切片
    var b = []int{1,2,3}    //声明一个切片并且初始化
    a = []int{1,3,5}
    fmt.Println(a)  //[1 3 5]
    fmt.Println(b)  //[1 2 3]
    //从数组中定义
    c := [4]int{1,2,3,4}
    c1 := c[0:2]    //包含元素c[0],c[1],左包含右不包含
    fmt.Println(c1) //[1 2]
    fmt.Printf("type of c1:%T\n", c1)       //type of c1:[]int
    c2 := c[1:]     //从索引1开始切到最后
    c3 := c[:3]     //从开始切到索引为3(不包含3,3-1)
    fmt.Println(c2) //[2 3 4]
    fmt.Println(c3) //[1 2 3]

切片扩容

Go语言的内建函数append()可以为切片动态添加元素。
示例:

//切片扩容
    s := []int{}    //定义一个空切片
    //var s []int   //定义一个空切片
    for i:=0;i<10;i++{
        s = append(s, i)
        fmt.Printf("%v  len:%d  cap:%d ptr:%p\n",s,len(s),cap(s),s)
    }
//输出
[0]  len:1  cap:1 ptr:0xc42000e318
[0 1]  len:2  cap:2 ptr:0xc42000e340
[0 1 2]  len:3  cap:4 ptr:0xc42000a360
[0 1 2 3]  len:4  cap:4 ptr:0xc42000a360
[0 1 2 3 4]  len:5  cap:8 ptr:0xc4200161c0
[0 1 2 3 4 5]  len:6  cap:8 ptr:0xc4200161c0
[0 1 2 3 4 5 6]  len:7  cap:8 ptr:0xc4200161c0
[0 1 2 3 4 5 6 7]  len:8  cap:8 ptr:0xc4200161c0
[0 1 2 3 4 5 6 7 8]  len:9  cap:16 ptr:0xc42007a000
[0 1 2 3 4 5 6 7 8 9]  len:10  cap:16 ptr:0xc42007a000
  • append()函数将元素追加到切片的最后并返回该切片。
  • 切片numSlice的容量按照1,2,4,8,16这样的规则自动进行扩容。
  • 如果新申请容量(cap)大于2倍的旧容量(old.cap),最终容量(newcap)就是新申请的容量(cap)。
  • 如果旧切片的长度小于1024,则最终容量(newcap)就是旧容量(old.cap)的两倍,即(newcap=doublecap)
  • 如果旧切片长度大于等于1024,则最终容量(newcap)从旧容量(old.cap)开始循环增加原来的1/4,即(newcap=old.cap,for {newcap += newcap/4})直到最终容量(newcap)大于等于新申请的容量(cap),即(newcap >= cap)
  • 如果最终容量(cap)计算值溢出,则最终容量(cap)就是新申请容量(cap)。

切片是引用类型

//对一个切片的修改会影响另一个切片的内容
    a := []int{1,2,3}
    b := a  //直接赋值
    b[1] = 10
    fmt.Println(a)  //[1 10 3]
    fmt.Println(b)  //[1 10 3]

由于切片是引用类型,所以a和b其实都指向了同一块内存地址。修改b的同时a的值也会发生变化。

make()函数构造切片

如果需要动态的创建一个切片,我们就需要使用内置的make()函数。
语法:make([]T, size, cap)
T:切片的元素类型
size:切片中元素的数量
cap:切片的容量
make用于给引用类型申请内存空间
切片必须初始化,或者用append才能使用

//make函数
    s := make([]int,2,5)
    fmt.Println(s)      //[0 0]
    fmt.Println(len(s)) //2
    fmt.Println(cap(s)) //5

s的内部存储空间已经分配了5个,但实际上只用了2个.

copy()函数复制切片

Go语言内建的copy()函数可以迅速地将一个切片的数据复制到另外一个切片空间中,修改copy后切片的值不会影响原切片。
语法:copy(destSlice, srcSlice []T)
srcSlice: 数据来源切片
destSlice: 目标切片

a := []string{"北京","上海"}
    var b []string  //还没有申请内存,所以打印为[]
    copy(b,a)
    fmt.Println(a)  //[北京 上海]
    fmt.Println(b)  //[]
    c := make([]string,3,3)
    copy(c,a)
    fmt.Println(c)      //[北京 上海 ]
    c[0] = "青岛"
    fmt.Println(c)      //[青岛 上海 ]
    fmt.Println(a)      //[北京 上海]

切片删除元素

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

//切片中删除元素
    d := []int{1,2,3,4,5,6,7}
    //删除索引为2的元素
    d = append(d[:2],d[3:]...)
    fmt.Println(d)  //[1 2 4 5 6 7]

总结:要从切片a中删除索引为index的元素,操作方法是a = append(a[:index], a[index+1:]...)

切片遍历

支持索引遍历和for range遍历。

//切片遍历
    a1 := []string{"北京","上海"}
    for i:=0;i<len(a1);i++{
        fmt.Println(a1[i])
    }
    for k,v :=range a1{
        fmt.Println(k,v)
    }
posted @ 2019-04-08 16:23  我是一条最咸的咸鱼  阅读(378)  评论(0编辑  收藏  举报
返回顶部