1.簡介
切片是數組的一個引用,因此切片是引用類型,在進行傳遞時,遵守引用傳遞的機制。切片的使用和數組類似,遍歷切片、訪問切片的元素和切片的長度都一樣。。切片的長度是可以變化的,因此切片是一個可以動態變化的數組。
2.切片的定義基本語法
var 切片名 []類型
比如:var a []int
3.切片的初始化
3.1方式一
第一種方式:定義一個切片,然后讓切片去引用一個已經創建好的數組。
var arr = [...]int{1, 2, 3, 4, 5, 6}slice := arr[1:3]slice[0] = 100fmt.Println("arr:", arr)fmt.Println("slice:", slice)fmt.Println("slice長度:", len(slice))fmt.Println("slice容量:", cap(slice))
結果:
arr: [1 100 3 4 5 6]
slice: [100 3]
slice長度: 2
slice容量: 5
根據上面結果分析:切片的確是一個引用類型,改變slice的值會影響原數組。
其實切片底層其實就是一個數據結構
type slice struct{
ptr *[2]int
len int
cap int? }
3.2方式二
第二種方式:通過make來創建切片。
基本語法:var 切片名 []type=make([]type ,len,cap)
參數說明:type:就是數據類型 len:大小 cap:值切片的容量,可選,如果你分配了cap,則要求cap>=len。
var SliceA = make([]int, 5, 6)SliceA[0] = 1fmt.Println(SliceA) //[0 0 0 0 0]fmt.Printf("長度:%d-容量%d", len(SliceA), cap(SliceA))
結果:
[1 0 0 0 0]
長度:5-容量6
對上面代碼小結:
1.通過make方式創建切片可以指定切片的大小和容量。
2.如果沒給切片的各個元素賦值,那么就會使用使用默認值 int 0 float 0? string “” bool false。
3.通過make方式船艦的切片對應的數組由make底層維護,對外不可見,即只能通過slice去訪問各個元素。
3.3方式三
定義一個切片,直接指定具體的數組,使用原理類似make的方式。
var strSlice = []string{"java", "php", "golang"}fmt.Println(strSlice)fmt.Printf("類型:%T\n", strSlice)fmt.Println("長度:", len(strSlice))fmt.Println("容量:", cap(strSlice))
?結果:
[java php golang]
類型:[]string
長度: 3
容量: 3
3.4方式一和方式二的區別
1.方式一是直接引用數組,這個數組是事先存在的,程序員可見的。
2.方式二是通過make來創建切片,make也會船艦一個數組,是由七篇在底層進行維護的,程序員是看不見的。make創建切片的示意圖:
4.切片的擴容?
4.1append擴容
聲明一個切片,golang中沒辦法通過下標方式給切片擴容,需要用到append()方法.比如
var sliceB []intsliceB[0] = 2 //golang中沒辦法通過下標方式給切片擴容,需要用到append()方法.
會報錯:panic: runtime error: index out of range [0] with length 0
var sliceB []intsliceB = append(sliceB, 1)sliceB = append(sliceB, 123, 35, 67)fmt.Println(sliceB)fmt.Printf("長度:%v-容量:%v-%v-%T\n", len(sliceB), cap(sliceB), sliceB, sliceB)
結果:
[1 123 35 67]
長度:4-容量:4-[1 123 35 67]-[]int
4.2append方法合并切片
sliceC := []string{"java", "go", "php"}sliceD := []string{"javad", "god", "phpd"}sliceC = append(sliceC, sliceD...)fmt.Println(sliceC)
?結果:
[java go php javad god phpd]
4.3切片的copy
已知切片是引用類型,更改切片的值會影響其他使用該切片的地方。
sliceA := []string{"java", "php"}sleceB := sliceAvar sliceC = make([]string, 2, 2)//copy()切片的復制copy(sliceC, sliceA)sleceB[0] = "golang"fmt.Println("sliceA:", sliceA)fmt.Println("sleceB:", sleceB)fmt.Println("sliceC:", sliceC)
結果:由結果可以看出,當sliceB改變了,對sliceC沒有任何影響。
sliceA: [golang php]
sleceB: [golang php]
sliceC: [java php]
4.4切片的刪除
刪除下標為二的數據。
a := []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 0}a = append(a[:2], a[3:]...)fmt.Println(a)
?結果:
[1 2 4 5 6 7 8 9 0]
?4.5切片cap容量的理解
切片的容量是從他的第一個元素開始數,到其底層數組元素末尾的個數。
示例1:
a := [8]int{0, 1, 2, 3, 4, 5, 6, 7} // 引用的底層數組s1 := a[0:5]fmt.Printf("長度:%v-容量:%v\n", len(s1), cap(s1))
結果:由結果可知長度5容量8,a[0:5],從數組a第一個下標一直數到a數組的末尾個數0-7即cap=8.
長度:5-容量:8
?
?示例2:
a := [8]int{0, 1, 2, 3, 4, 5, 6, 7} // 引用的底層數組s2 := a[3:6]fmt.Printf("長度:%v-容量:%v\n", len(s2), cap(s2))
結果:由結果可知長度3容量5,a[3:6],從數組a第一個下標一直數到a數組的末尾個數3-7即cap=5.
長度:3-容量:5
5.切片的遍歷?
切片的遍歷和數組一樣,也有兩種方式。
方式1:
for i := 0; i < len(slice); i++ {fmt.Println(slice[i])}
方式2:
slice := []int{1, 2, 3, 4, 5, 6, 7, 8, 9}for _, value := range slice {fmt.Println(value)}
結果:
1
2
3
4
5
6
7
8
9
6.切片的使用注意事項和細節討論
7.1切片初始化是var slice=arr[stratIndex:endIndex]
說明:從arr數組小標圍毆startIndex,取到下標為endIndex的元素,不包含arr[endIndex]
7.2切片初始化是,仍然不能越界。范圍在[0-len(arr)]之間,但可以動態增長。
參考4.1append擴容
7.3cap是一個內置函數,用于統計切片的容量,即最大可以存放多少個元素。
?參考:4.5切片cap容量的理解
7.4切片定義完后,還不能直接使用,因為本身是一個空的,需要讓你、昂起引用到一個數組,或者,make?一個空間供切片使用。
7.5切片可以繼續切片
A := []int{1, 2, 3, 4, 5, 6, 7, 8}B := A[3:8]C := A[:5]fmt.Println("B:", B)fmt.Println("C:", C)
結果:
B: [4 5 6 7 8]
C: [1 2 3 4 5]
7.6append()內置函數,可以對切片進行動態追加
用法:參考4.1、4.2
?切片append操作的底層原理分析:
切片append操作的本質就是對數組擴容,go底層會創建新的數組newArr(安裝擴容后的大小),
將slice原來包含的元素拷貝到新的數組newArr,slice重新引用到newArr,注意newarr是底層來維護的,程序員不可見。
7.7 關于拷貝的注意事項
var a []int = []int{1, 2, 3, 4, 5}var slice = make([]int, 1)copy(slice, a)fmt.Println(slice)
結果:
[1]
說明,上面代碼沒有問題,可以運行,最后輸出的是[1]