Golang學習筆記之切片(slice)
切片slice:切片是對陣列的抽象。切片在記憶體中佔24個位元組
runtime.h struct Slice{// must not move anything byte* array;// actual data uintgo len;// number of elements uintgo cap;// allocated number of elements };
切片包含長度、容量、以及一個指向首元素的指標
• 引⽤型別。但⾃⾝是結構體,值拷⻉傳遞。
• 屬性 len 表⽰可⽤元素數量,讀寫操作不能超過該限制。
• 屬性 cap 表⽰最⼤擴張容量,不能超出陣列限制。
• 如果 slice == nil,那麼 len、 cap 結果都等於 0。
• 作為變長陣列的替代方案,可以關聯底層陣列的區域性或全部
•可以直接建立或從底層陣列獲取生成
• 使用len()獲取元素個數,cap()獲取容量
• 一般使用make()建立
•如果多個slice指向相同底層陣列,其中一個值的改變會影響全部
•在通過下標訪問元素時下標不能超過len大小,如同陣列的下標不能超出len範圍一樣。
make([]T, len, cap)
其中cap可以省略,則和len的值相同
len表示存放的元素個數,cap表示容量
1、初始化的幾種方式
//第一種方式建立切片 var slice []int fmt.Println(len(slice)) //0 //第二種方式 sl1 := []int{0, 1, 2, 3, 8: 100}// 通過初始化表示式構造,可使⽤索引號。 fmt.Println(sl1, len(sl1), cap(sl1)) //[0 1 2 3 0 0 0 0 100] 9 9 sl2 := make([]int, 10) // 使⽤ make 建立,省略 cap,相當於 cap = len。 fmt.Println(sl2)//[0 0 0 0 0 0 0 0 0 0] //第三種方式 num := []int{10, 20, 30, 40, 50} fmt.Println(num) //[10 20 30 40 50]
2、append
向 slice 尾部新增資料,返回新的 slice 物件
切片可以通過內建函式append(slice []Type,elems …Type)追加元素,elems可以是一排type型別的資料,也可以是slice,因為追加的一個一個的元素,因此如果將一個slice追加到另一個slice中需要帶上”…”,這樣才能表示是將slice中的元素依次追加到另一個slice中。append追加元素超出實際容量會執行擴容,會擴充套件為slice原先容量的2倍
(1)//將一個slice追加到另一個slice中需要帶上”…”,這樣表示是將slice中的元素依次追加到另一個slice中
例:
veggies := []string{"potatoes", "tomatoes", "brinjal"} fruits := []string{"oranges", "apples"} food := append(veggies, fruits...) //veggies+fruits fmt.Println("food:", food)
(2)切片元素刪除,可以使用append來實現
s = append(s[:i], s[i+1:]…)
首先s[:i]相當於slice擷取,也就是說s[:i]本身就是一個slice。然後s[i+1:]…相當於變長引數。使用append的特性(向 slice 尾部新增資料,返回新的 slice 物件)來實現刪除的功能。可以單個也可以刪除多個。
例:
//刪除scile中元素,刪除下標為2的元素 test := []int{10, 20, 30, 40, 50, 100} test = append(test[:2], test[3:]...) fmt.Println(test) //[10 20 40 50 100]
3、copy
函式 copy 在兩個 slice 間複製資料,複製⻓度以 len ⼩的為準。兩個 slice 可指向同⼀底層陣列,允許元素區間重疊。
例:
//copy countries := []string{"USA", "Singapore", "Germany", "India", "Australia"} neededCountries := countries[:len(countries)-2] countriesCpy := make([]string, len(neededCountries)) copy(countriesCpy, neededCountries) fmt.Println(countriesCpy) fmt.Println(len(countriesCpy), cap(countriesCpy)) data := [...]int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9} s := data[8:] s2 := data[:5] copy(s2, s)// dst:s2, src:s fmt.Println(s2)//[8 9 2 3 4] fmt.Println(data) //[8 9 2 3 4 5 6 7 8 9]
應及時將所需資料 copy 到較⼩的 slice,以便釋放記憶體。
下面是整個例子
package main import ( "fmt" "unsafe" ) func main() { //第一種方式建立切片 var slice []int fmt.Println(len(slice)) //0 //第二種方式 sl1 := []int{0, 1, 2, 3, 8: 100}// 通過初始化表示式構造,可使⽤索引號。 fmt.Println(sl1, len(sl1), cap(sl1)) //[0 1 2 3 0 0 0 0 100] 9 9 sl2 := make([]int, 10) // 使⽤ make 建立,省略 cap,相當於 cap = len。 fmt.Println(sl2)//[0 0 0 0 0 0 0 0 0 0] //第三種方式 num := []int{10, 20, 30, 40, 50} fmt.Println(num) //[10 20 30 40 50] fmt.Printf("type is %T\tsize is %d\n", sl2, unsafe.Sizeof(sl2)) var b []int b = num[1:4] //左閉右開從num下標1到3 var b1 []int b1 = num[:] //num的全部 fmt.Println(b) fmt.Println(b1) //切片為陣列的引用 darr := [...]int{57, 89, 90, 82, 100, 78, 67, 69, 59} dslice := darr[2:5] fmt.Println("array before", darr) for i := range dslice { dslice[i]++ } fmt.Println("array after", darr) //切片指向陣列,容量cap會從strartIndex取到陣列結束,長度是指定擷取長度 fruitarray := [...]string{"apple", "orange", "grape", "mango", "water melon", "pine apple", "chikoo"} fruitslice := fruitarray[0:3] //長度2容量6 fmt.Printf("length of slice %d capacity %d", len(fruitslice), cap(fruitslice)) //append追加元素超出實際容量會執行擴容,會擴充套件為原先容量的2倍 slice1 := make([]int, 5, 10) fmt.Println(slice1) slice3 := append(slice1, 1, 2, 3, 4, 5) fmt.Println(slice3) //執行append會會返回一個新的數值可以用原切片接收也可以使用別的 var slice4 []int //空的切片初始為nil fmt.Println(slice4) if slice4 == nil { slice4 = append(slice4, 1, 2, 3, 4) fmt.Println(slice4) } //將一個slice追加到另一個slice中需要帶上"…",這樣表示是將slice中的元素依次追加到另一個slice中 veggies := []string{"potatoes", "tomatoes", "brinjal"} fruits := []string{"oranges", "apples"} food := append(veggies, fruits...) //veggies+fruits fmt.Println("food:", food) //二維切片,每一行元素的個數可以不一致 pls := [][]string{ {"C", "C++"}, {"JavaScript"}, {"Go", "Rust"}, } fmt.Println(len(pls), cap(pls)) //長度為3容量為3 for _, v1 := range pls { for _, v2 := range v1 { fmt.Printf("%s ", v2) } fmt.Printf("\n") } //copy countries := []string{"USA", "Singapore", "Germany", "India", "Australia"} neededCountries := countries[:len(countries)-2] countriesCpy := make([]string, len(neededCountries)) copy(countriesCpy, neededCountries) fmt.Println(countriesCpy) fmt.Println(len(countriesCpy), cap(countriesCpy)) data := [...]int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9} s := data[8:] s2 := data[:5] copy(s2, s)// dst:s2, src:s fmt.Println(s2)//[8 9 2 3 4] fmt.Println(data) //[8 9 2 3 4 5 6 7 8 9] //刪除scile中元素,刪除下標為2的元素 test := []int{10, 20, 30, 40, 50, 100} test = append(test[:2], test[3:]...) fmt.Println(test) //[10 20 40 50 100] }