標籤:位元組 png www. .com ref image ges 注意 對比
上一篇 詳解go語言的array和slice 【一】已經講解過,array和slice的一些基本用法,使用array和slice時需要注意的地方,特別是slice需要注意的地方比較多。上一篇的最後講解到建立新的slice時使用第三個索引來限制slice的容量,在操作新slice時,如果新slice的容量大於長度時,添加新元素依然後使源的相應元素改變。這一篇裡我會講解到如何避免這些問題,以及迭代、和做為方法參數方面的知識點。
slice的長度和容量設定為同一個值
如果在建立新的slice時我們把他的長度和容量的值設定為樣的值,那麼在append新元素時,底層會建立一個新的array並把之前的值複製過去。這樣就不會影響之前共同的底層array了。
// 建立一個容量和長度均為6的slice slice1 := []int{5, 23, 10, 2, 61, 33} // 對slices1進行切片,長度為2容量為3 slice2 := slice1[1:3:3] fmt.Println("cap", cap(slice2)) fmt.Println("slice2", slice2) //修改一個共同指向的元素 //兩個slice的值都會修改 slice2[0] = 11111 fmt.Println("slice1", slice1) fmt.Println("slice2", slice2) // 增加一個元素 slice2 = append(slice2, 55555) fmt.Println("slice1: ", slice1) fmt.Println("slice2: ", slice2)
輸出結果
cap 2slice2 [23 10]slice1 [5 11111 10 2 61 33]slice2 [11111 10]slice1: [5 11111 10 2 61 33]slice2: [11111 10 55555]
代碼中的長度和容量是一樣的,長度和容量的計算公式看我的上一篇部落格。增加一個元素後,原來共同指向的底層資料是沒有變的。因為slice2的底層array被重新賦值了。
迭代slice
go語言內建一個關鍵字range用於迭代集合,當然他也可以迭代slice,也可以使用 _ 來忽略我們不關心的元素,但是如果只關心index則不需這麼寫 for index,_ := range slice1。下在給出完整代碼
// 建立一個容量和長度均為6的slice slice1 := []int{5, 23, 10, 2, 61, 33} for index, value := range slice1 { fmt.Println("index: ", index, " value: ", value) } // 可以忽略我們不關心的元素 // 只關心value for _, value := range slice1 { fmt.Println("value ", value) } // 只關心index, 可以不用 _ for index := range slice1 { fmt.Println("index: ", index) }
需要注意的是rang 迭代的value值並是一個複本,我們可以對比一下迭代的value和原slice內相應index下value的地址:
// 建立一個容量和長度均為6的slice slice1 := []int{5, 23, 10, 2, 61, 33} for index, value := range slice1 { fmt.Println("index: ", index, " value address : ", &value, " slice1 value address", &slice1[index]) }
輸出結果
index: 0 value address : 0xc04204e088 slice1 value address 0xc04206a030index: 1 value address : 0xc04204e088 slice1 value address 0xc04206a038index: 2 value address : 0xc04204e088 slice1 value address 0xc04206a040index: 3 value address : 0xc04204e088 slice1 value address 0xc04206a048index: 4 value address : 0xc04204e088 slice1 value address 0xc04206a050index: 5 value address : 0xc04204e088 slice1 value address 0xc04206a058
slice1中value的地址是不斷變化的。而迭代的value值的地址沒有變化,這是因為value是一個變數,為次迭代的時候賦不同的值。我們把代碼寫成下面這樣,你就清楚了
var index, value int for index, value = range slice1 { fmt.Println("index: ", index, &index, " value address : ", &value, " slice1 value address", &slice1[index]) }
除了使用rang 也可以使用傳統的for迴圈來做迭代
slice1 := []int{5, 23, 10, 2, 61, 33} for i, len := 1, len(slice1); i < len; i++ { fmt.Println("index: ", i, " value:", slice1[i]) }
slice作為方法參數
由於slice的特殊結構,有一個指標指向一個數組
s := make([]int, 2, 5) fmt.Println("len: ", len(s)) fmt.Println("cap: ", cap(s)) s = append(s, 2) s[0] = 12
所以,slice做為方法的參數傳遞時,只會複製slice本身而不會複製slice底層的array.如果我們建立一個int類型有100萬長度的slice ,把他傳遞給一個方法時,只需要複製24個位元組就夠了。指標需要8個,長度和容量都是8個。
const size int = 1000 * 1000func main() { slice0 := make([]int, size) fmt.Println("slice0 len: ", len(slice0), " cap :", cap(slice0)) doSomeThing(slice0)}func doSomeThing(s []int) { fmt.Println(len(s))}
詳解go語言的array和slice 【二】