標籤:切片slice
切片Slice理論知識
- 其本身並不是數組,它指向底層的數組
- 作為編程數組的替代方案,可以關聯底層數組的局部或者全部
- 為參考型別
- 可以直接建立或從底層數組擷取產生
- 使用len()擷取元素個數,cap()擷取容量
- 一般使用make()建立
- 如果多個slice指向相同底層數組,其中一個的值改變會影響全部
- make([]T, len, cap)
- 其中,cap可以省略,則和len的值相同
- len表示存數的元素個數,cap表示容量
slice與底層數組的關係
Reslice
- Reslice時索引以被slice的切片為準
- 索引不可以超過被slice的切片的容量cap()的值
- 索引越界不會導致底層數組的重新分配而是引發錯誤
Append
- 可以在slice尾部追加元素
- 可以將一個slice追加在另一個slice尾部
- 如果最終長度未超過追加到slice的容量則返回原始slice
- 如果超過追加到的slice的容量則將重新分配數組並拷貝未經處理資料
Copy
//切片slice 練習package mainimport "fmt"func main() { //============先建立一個數組==== // 建立數組,必須指明個數 age := [4]int{} fmt.Println(age) //=========聲明一個切片Slice類型===== // 看見了吧,切片類型,是不需要指明 個數的 // 記住,slice類型的底層,也是數組 var s1 []float64 fmt.Println(s1) //========方式一:利用已有的數組,來初始化s1 sparkNodeCpu := [...]float64{4.5, 3.4, 2.3, 9.8, 10} s1 = sparkNodeCpu[3:5] //從下標為3的元素,開始擷取 fmt.Println("------------->\t", s1) s1 = sparkNodeCpu[1:] //從下標為1的元素,擷取到 最後 fmt.Println(s1) s1 = sparkNodeCpu[:4] //指定最後一個擷取的元素 fmt.Println(s1) //========方式二:利用make關鍵字,來建立切片 //make([]T, len, cap) //[]T,表示切片的類型 //len,表示當前元素的個數,或者,初始化的個數 //cap,由於切片的底層其實是數組,而數組在記憶體裡是一塊連續的空間, // 如make([]int, 3,10) 為了提升效率,一般先在記憶體裡建立 // 一塊連續的記憶體大小,為10,如果你的元素個數超過了10的話, //Go語言,會預設將你現在的記憶體空間,由10,增加到20,重新在記憶體裡找一塊連續的空間,分配20個空間 // 如果又超過20的話,就分配40,就這麼下去。因此,最好你知道你需要多大的記憶體空間 s2 := make([]int, 3, 10) fmt.Println(len(s2), cap(s2)) // 3 10 s2a := make([]int, 3) // 也可以不指定cap,這樣的話,cap的預設值,就是len的長度 fmt.Println(len(s2a), cap(s2a)) // 3 3 //=======================Reslice========練習===== // 先聲明一個切片類型 a := []rune{‘a‘, ‘b‘, ‘c‘, ‘d‘, ‘e‘, ‘f‘, ‘j‘, ‘k‘, ‘u‘} //以原切片a為基礎,開始切 //此時,你要注意了,新產生的切片s3的容量 //下面的操作就是Reslice s3 := a[2:5] //表示,從下標為2開始,到5結束,最大不能超過被切slice的cap容量7 s3a := s3[3:5] fmt.Println("長度:\t", len(s3), "\t容量cap:\t", cap(s3)) //3 7 fmt.Println("長度:\t", len(s3a), "\t容量cap:\t", cap(s3a)) //2 4 fmt.Println(string(s3a)) //=======================Append========練習===== slice1 := make([]int, 3, 6) //預設值是全是0 fmt.Printf("先列印出slice1的記憶體位址:\t %p\n", slice1) // 0xc042078090 //先追加3個元素 slice1 = append(slice1, 1, 3, 5) //再列印出slice1的值,和 記憶體位址 fmt.Printf("%v %p\n", slice1, slice1) //[0 0 0 1 3 5] 0xc042078090 //繼續追加元素,查看,記憶體位址,是否發生了變化 slice1 = append(slice1, 4, 5, 6) // 超過了slice1的容量後,重新分配了記憶體位址 fmt.Printf("%v %p\n", slice1, slice1) //[0 0 0 1 3 5 4 5 6] 0xc042056060 fmt.Println("=======================================") //測試,當多個切片都指向同一個底層數組時,並且多個切片有共同的元素時,如果其中一個元素,發生變化的話, //其他切片也會發生變化的 appleSlice := []int{3, 4, 5, 9, 8, 7} bananaS := appleSlice[3:6] orangeS := appleSlice[2:5] //bananaS orangeS 有兩個共同的元素 fmt.Println(appleSlice) //[3 4 5 9 8 7] fmt.Println(bananaS) //[9 8 7] fmt.Println(orangeS) //[5 9 8] fmt.Println("=======================================") //假設bananaS切片裡的元素,第1個元素,發生了變化的話, //測試,appleSlice,orangeS 是否也發生了變呢 //我改動的是下標為1,值為8的元素,將8改為了110,與此同時,其他切片中,8的值也全都改成了110了 bananaS[1] = 110 //將下標為1的元素,設定為110 fmt.Println(appleSlice) //[3 4 5 9 110 7] fmt.Println(bananaS) //[9 110 7] fmt.Println(orangeS) //[5 9 110] fmt.Println("=======================================") // 注意,此時,orangeS,orangeS 依舊都執行底層的數組appleSlice //還要注意下面的情形 //利用Append方法 bananaS = append( bananaS, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7) //此時,bananaS已經不再指向appleSlice了,因為超過了appleSlice的容量 //而是,指向了新的地址,此時,我們再修改bananaS bananaS[1] = 1110 fmt.Println(appleSlice) //[3 4 5 9 110 7] //看見了把,僅僅是修改了自己的值,appleSlice,orangeS 並沒有發生變化 fmt.Println(bananaS) //[9 1110 7 7 7 7 7 7 7 7 7 7 7 7 7 7] fmt.Println(orangeS) //[5 9 110] fmt.Println("=======================================") //=======================Copy========練習===== // copy(A,B) 是說,將B裡的元素,拷貝到A裡 ftpNum := []int{4, 6, 7, 2, 3, 8, 9} sftpNum := []int{1, 2, 3} //將sftp copy(ftpNum, sftpNum) //注意,copy之後,就會將原先的值該了 fmt.Println(ftpNum) fmt.Println(sftpNum) //截取拷貝 copy(sftpNum[1:2], ftpNum[2:3]) fmt.Println(ftpNum) fmt.Println(sftpNum)}
Go語言之切片Slice練習