Go之集合slice的實現

Slice(切片)

切片和數組類似,可以把它理解為動態數組。切片是基於數組實現的,它的底層就是一個數組。對數組任意分隔,就可以得到一個切片。現在我們通過一個例子來更好地理解它,同樣還是基於前面的 array。

基於數組生成切片

下面代碼中的 array[2:5] 就是獲取一個切片的操作,它包含從數組 array 的索引 2 開始到索引 5 結束的元素:

array:=[5]string{"a","b","c","d","e"}
slice:=array[2:5]
fmt.Println(slice)

註意:這裡是包含索引 2,但是不包含索引 5 的元素,即在 : 右邊的數字不會被包含。

//基於數組生成切片,包含索引start,但是不包含索引end

slice:=array[start:end]

所以 array[2:5] 獲取到的是 c、d、e 這三個元素,然後這三個元素作為一個切片賦值給變量 slice。

切片和數組一樣,也可以通過索引定位元素。這裡以新獲取的 slice 切片為例,slice[0] 的值為 c,slice[1] 的值為 d。
有沒有發現,在數組 array 中,元素 c 的索引其實是 2,但是對數組切片後,在新生成的切片 slice 中,它的索引是 0,這就是切片。雖然切片底層用的也是 array 數組,但是經過切片後,切片的索引范圍改變瞭。

通過下圖可以看出,切片是一個具備三個字段的數據結構,分別是指向數組的指針 data,長度 len 和容量 cap:

這裡有一些小技巧,切片表達式 array[start:end] 中的 start 和 end 索引都是可以省略的,如果省略 start,那麼 start 的值默認為 0,如果省略 end,那麼 end 的默認值為數組的長度。如下面的示例:

  • array[:4] 等價於 array[0:4]。
  • array[1:] 等價於 array[1:5]。
  • array[:] 等價於 array[0:5]。

切片修改

切片的值也可以被修改,這裡也同時可以證明切片的底層是數組。
對切片相應的索引元素賦值就是修改,在下面的代碼中,把切片 slice 索引 1 的值修改為 f,然後打印輸出數組 array:

slice:=array[2:5]
slice[1] ="f"
fmt.Println(array)

可以看到如下結果:

[a b c f e]

數組對應的值已經被修改為 f,所以這也證明瞭基於數組的切片,使用的底層數組還是原來的數組,一旦修改切片的元素值,那麼底層數組對應的值也會被修改。

切片聲明

除瞭可以從一個數組得到切片外,還可以聲明切片,比較簡單的是使用 make 函數。
下面的代碼是聲明瞭一個元素類型為 string 的切片,長度是 4,make 函數還可以傳入一個容量參數:

slice1:=make([]string,4)

在下面的例子中,指定瞭新創建的切片 []string 容量為 8:

slice1:=make([]string,4,8)

這裡需要註意的是,切片的容量不能比切片的長度小。

切片的長度你已經知道瞭,就是切片內元素的個數。那麼容量是什麼呢?其實就是切片的空間。

上面的示例說明,Go 語言在內存上劃分瞭一塊容量為 8 的內容空間(容量為 8),但是隻有 4 個內存空間才有元素(長度為 4),其他的內存空間處於空閑狀態,當通過 append 函數往切片中追加元素的時候,會追加到空閑的內存上,當切片的長度要超過容量的時候,會進行擴容。

切片不僅可以通過 make 函數聲明,也可以通過字面量的方式聲明和初始化,如下所示:

slice1:=[]string{"a","b","c","d","e"}
fmt.Println(len(slice1),cap(slice1))

可以註意到,切片和數組的字面量初始化方式,差別就是中括號 [] 裡的長度。此外,通過字面量初始化的切片,長度和容量相同。

Append

我們可以通過內置的 append 函數對一個切片追加元素,返回新切片,如下面的代碼所示:

//追加一個元素
slice2:=append(slice1,"f")
//多加多個元素
slice2:=append(slice1,"f","g")
//追加另一個切片
slice2:=append(slice1,slice...)

append 函數可以有以上三種操作,你可以根據自己的實際需求進行選擇,append 會自動處理切片容量不足需要擴容的問題。

小技巧:在創建新切片的時候,最好要讓新切片的長度和容量一樣,這樣在追加操作的時候就會生成新的底層數組,從而和原有數組分離,就不會因為共用底層數組導致修改內容的時候影響多個切片。

切片元素循環

切片的循環和數組一模一樣,常用的也是 for range 方式,這裡就不再進行舉例,當作練習題留給你。
在 Go 語言開發中,切片是使用最多的,尤其是作為函數的參數時,相比數組,通常會優先選擇切片,因為它高效,內存占用小。

到此這篇關於Go之集合slice的實現的文章就介紹到這瞭,更多相關Go 集合slice內容請搜索WalkonNet以前的文章或繼續瀏覽下面的相關文章希望大傢以後多多支持WalkonNet!

推薦閱讀: