這是一個建立於 的文章,其中的資訊可能已經有所發展或是發生改變。
Slice是Go語言提供的一種方便並且高效的有序資料類型,就和其他語言的數組類似,但是又有一些其他的特性。
Go數組:
因為Slice是建立在Go數組的抽象層上的,所以,要學習Slice,我們先來看一下Go語言的數組:
一個數組定義了一個具有特定長度和資料類型的資料。例如:【4】int 就代表了一個有4個int類型的數組。數組的大小是確定的,數組的長度是數群組類型的一部分(【4】int和【5】int是完全不同的類型)。數組可以像其他語言那樣索引,s【n】能夠訪問第n個元素:
var a [4]inta[0] = 1i := a[0]// i == 1
數組不需要明確的初始化,沒有初始化的項,將用0作為預設值
// a[2] == 0, the zero value of the int type
【4】int的記憶體結構如:
Go語言的數組是值定義的,而不是指標。一個陣列變數就代表了整個數組,而不是一個指向第一個數組元素的指標(像c語言那樣)。這就意味著,當需要傳遞一個數組的時候,我們應該傳遞這個數組的整個內容,也就是拷貝這個數組的整個內容。(為了避免拷貝的麻煩,我們可以傳遞一個指向數組的指標,但是需要注意的是:這樣做了之後,這個指標就僅僅是一個指標而已,而不是一個數組)
一個字串數組可以這樣定義:
b := [2]string{"Penn", "Teller"}
或者,可以讓編譯器幫我們統計元素的個數:
b := [...]string{"Penn", "Teller"}
這兩種方法都是等價的。
Slices:
數組擁有自己的記憶體空間,這個記憶體空間是一個整體,不能分割的。因為這個原因,Go中用了大量的Slices而不是數組。聲明一個slices的方法:【】T,T是slice中元素的類型,和數組不同,slice是不需要指定長度的。聲明一個字元類型的slice的方法和聲明一個數組差不多,只是不指定元素個數而已:
letters := []string{"a", "b", "c", "d"}
slice也可以用Go內部庫函數make來建立,make是具有簽名功能的:
func make([]T, len, cap) []T
T表示元素的類型,make函數有3個參數,T元素的類型,len長度,cap容量(cap可選)。當make被調用的時候,make分配一下數組並且返回一個根據這個數組生產的slice。如果不填寫cap,那麼預設的情況下cap=len,一種簡潔的make的寫法是:
s := make([]byte, 5)
可以用Go的庫函數,len和cap來擷取slice的len和cap:
len(s) == 5cap(s) == 5
slice的0值為nil,如果一個slice等於nil,那麼len和cap都會返回0.
我們同樣可以用一個已經存在的數組或者slice來建立一個新的slice,例如:
a :=b【n:m】,表示a取b中從n到m-1的元素。
例如:
b := []byte{'g', 'o', 'l', 'a', 'n', 'g'}// b[1:4] == []byte{'o', 'l', 'a'}, sharing the same storage as b
擷取Slice片段的時候,預設的開始值是0,預設的結束是該slice的長度,例如:
b := []byte{'g', 'o', 'l', 'a', 'n', 'g'}
b[:2] == []byte{'g', 'o'}b[2:] == []byte{'l', 'a', 'n', 'g'}b[:] == b
同樣的,slice也可以用數組來建立:
x := [3]string{"Лайка", "Белка", "Стрелка"}s := x[:] // a slice referencing the storage of x
slice的儲存結構:
一個slice描述了一個數組的片段,一個slice包括:指向數組的指標,該段的長度,容量(段的最大長度)
s := make([]byte, 5)的儲存結構如下:
再次明確一下,len是slice中item的個數,cap是slice所指向的數組的長度(從slice所指向的開始的位置開始,直到數組結尾),例如:
s = s[2:4]
在slice的基礎上建立新的slice,並不是做賦值操作,而是建立了一個新的指向相同數組的slice,例如:
d := []byte{'r', 'o', 'a', 'd'}e := d[2:] // e == []byte{'a', 'd'}e[1] = 'm'// e == []byte{'a', 'm'}// d == []byte{'r', 'o', 'a', 'm'}