Go的切片

切片

切片是由数组建立的一种方便、灵活且功能强大的包装(Wrapper)。切片本身不拥有任何数据。它们只是对现有数组的引用。

因此切片的类型是引用类型。

一、切片的创建

1、先创建数组,再引用

// 先创建一个数组
var lis [10]int= [10]int{1,2,3,4,5,6,7,8,9,10}
// 创建切片
var sli = lis[:]  // 从头到尾全切
fmt.Println(sli)  // [1 2 3 4 5 6 7 8 9 10]
fmt.Printf("%T",sli)  // []int  
// []内没有数字就是切片,有就是数组

2、直接创建切片

var a []int=[]int{1,2,3,4,5}  //切片初始化,类似于数组初始化

二、切片的修改

因为切片是引用类型,它是对数组的引用。所以切片的修改会影响原来的数组,数组的修改也会影响切片。

var lis [10]int= [10]int{1,2,3,4,5,6,7,8,9,10}

var b []int = lis[5:9]  // 索引取值,左开右闭
b[0]=999
lis[6]=888
fmt.Println(b)
fmt.Println(lis)

[999 888 8 9]
[1 2 3 4 5 999 888 8 9 10]

三、切片的长度和容量

len() :长度,现在有多少值
cap() :容量,总共能放多少值,为引用的数组长度-切片首位索引

var lis [10]int= [10]int{1,2,3,4,5,6,7,8,9,10}

var b []int = lis[5:9]  

fmt.Println(len(b))  // 4
fmt.Println(cap(b))  // 5  //(10-5)

四、使用make创建切片

用函数make([]T,len,cap)来创建切片类型的变量,就不用先创建数组了。

函数参数分别为:类型,长度和容量。

容量是可选参数, 默认值为切片长度。

make 函数原理为创建一个数组,并返回引用该数组的切片。

var sli []int=make([]int,3,4)
fmt.Println(len(sli))  // 3
fmt.Println(cap(sli))  // 4

五、切片的修改和追加

1、修改

像列表一样用[索引]取值,修改值。

var a []int=make([]int,3,4)
a[0]=999
a[2]=999    //切片用[]修改值,只能取最大长度修改,超出长度的容量不能用[]的方式取值修改

a[3]=100  // 不行!!!会报错

2、追加:append

使用函数 append(slice []T,x ... T)[]T 可以将新元素追加到切片上。它会有一个返回值,是追加后的新的切片,所以需要用一个值来接受一下。

var sli []int=make([]int,3,4)
sli = append(sli,444)
fmt.Println(len(sli))  // 4
fmt.Println(cap(sli))  // 4

如果append函数添加的值,使切片长度超过最大容量,则会创建一个新的底层数组取代原本切片引用的数组。

原切片的元素被复制到这个新数组中,并返回引用这个新数组的切片。

这个新数组的长度是旧切片容量的两倍。而新切片的容量就等于这个新数组的长度。

所以现在新切片的容量是旧切片的两倍。

此时修改新切片的元素就不会影响原数组了。

// make创建的切片的追加
var sli []int=make([]int,3,4)
fmt.Println(len(sli))  // 3
fmt.Println(cap(sli))  // 4

sli = append(sli,444)
fmt.Println(len(sli))  // 4
fmt.Println(cap(sli))  // 4

sli = append(sli,555)
fmt.Println(sli)       // [0 0 0 444 555]
fmt.Println(len(sli))  // 5
fmt.Println(cap(sli))  // 8

// 引用数组的切片的追加
var lis [10]int= [10]int{1,2,3,4,5,6,7,8,9,10}
var sli []int = lis[5:9]

fmt.Println(lis)       // [1 2 3 4 5 6 7 8 9 10]
fmt.Println(sli)       // [6 7 8 9]
fmt.Println(len(sli))  // 4
fmt.Println(cap(sli))  // 5

sli = append(sli,444)  
sli[2] = 888           // 切片影响原来的数组
fmt.Println(lis)       // [1 2 3 4 5 6 7 888 9 444]
fmt.Println(sli)       // [6 7 888 9 444]
fmt.Println(len(sli))  // 5
fmt.Println(cap(sli))  // 5

sli = append(sli,555)  
sli[1] = 777           // 新的切片不会影响原来的数组了
fmt.Println(lis)       // [1 2 3 4 5 6 7 888 9 444]
fmt.Println(sli)       // [6 777 888 9 444 555]
fmt.Println(len(sli))  // 6 
fmt.Println(cap(sli))  // 10 新切片的容量是旧切片的两倍

六、切片的函数传值

因为切片的类型是引用类型,因此传值后,改变值会影响原来的值。

var a []int=make([]int,4,5)
fmt.Println(a) // [0 0 0 0]      
test2(a)       // [111 0 0 0]
               // [111 0 0 0 555]
fmt.Println(a) // [111 0 0 0]


func test2(x []int)  {
    x[0] = 111        // 修改a变量地址里的值
    fmt.Println(x)    // [111 0 0 0]
    x = append(x,555) // copy的x的长度变化了,产生了新的切片
    fmt.Println(x)    // [111 0 0 0 555]
}

七、多维切片

一般直接初始化。

var a [][]int=[][]int{{1,2,3},{2,3},{4,5,5,6,7,8,9}}
fmt.Println(a)  // [[1 2 3] [2 3] [4 5 5 6 7 8 9]]

八、切片的copy

把一个切片的元素copy到另一个切片上。

用函数copy(dst(目标), src(源))

var a []int=make([]int,4,5)
var b []int =[]int{1,2,3,4,5}

fmt.Println(a)  // [0 0 0 0]  
fmt.Println(b)  // [1 2 3 4 5]

//把b的数据copy到a上
copy(a,b)
fmt.Println(a)  // [1 2 3 4]  // 长度有多少就接受多少
fmt.Println(b)  // [1 2 3 4 5]

--------------------------------------------------
var a []int=make([]int,6,7)
var b []int =[]int{1,2,3,4,5}

fmt.Println(a)  // [0 0 0 0 0 0]
fmt.Println(b)  // [1 2 3 4 5]

//把b的数据copy到a上
copy(a,b)
fmt.Println(a)  // [1 2 3 4 5 0]  // 不足的用默认值补齐
fmt.Println(b)  // [1 2 3 4 5]
posted @ 2020-03-29 21:45  Donner  阅读(141)  评论(0编辑  收藏  举报