數組的長度是固定的,切片是可變長的。編程
數組的類型字面量中必須有元素的類型和長度。數組的長度在聲明的時候必須給定,而且以後不會再改變,數組的長度是其類型的一部分。好比[1]string
和[2]string
就是2個不一樣的數組類型。數組
切片的類型字面量中只有元素的類型,而沒有長度。切片的長度能夠自動地隨着其中元素數量的增加而增加,但不會隨着元素數量的減小而減少。數據結構
能夠把切片看做是對數組的一層簡單封裝,由於在每一個切片額底層數據結構中,必定會包含一個數組。數組能夠叫作切片的底層數組,而切片能夠看作是對數組的某個連續片斷的引用。app
正由於「切片能夠看做是數組的某個連續片斷的引用」,Go語言的切片類型屬於引用類型。同屬於引用類型的還有字典類型,通道類型,函數類型等;而Go語言的數組類型則屬於值類型,同屬於值類型的還有基礎數據類型以及結構體類型。編程語言
Go語言裏不存在像Java等編程語言中使人困惑的「傳值或傳引用」問題。在Go語言中,咱們判斷所謂的「傳值」或者「傳引用」只要看傳遞的值的類型就行了,若是傳遞的值的類型是值類型,那麼就是「傳值」,若是傳遞的值的類型是引用類型的,那麼就是「傳引用」。從傳遞成本的角度講,引用類型的值每每要比值類型的值低不少。函數
能夠在數組和切片之上應用「索引表達式」,獲得的是某個元素。 也能夠在數組和切片上應用「切片表達式」,獲得的是一個新的切片。學習
調用內建函數len,能夠獲得數組和切片的長度。數組的容量永遠等於其長度,都是不可變的。 調用內建函數cap,能夠獲得數組和切片的容量。切片的容量是可變的,變化也是有規律可循的。code
內建函數make能夠建立切片。 make([]int,5,8)
第一個參數[]int
指明切片的類型,第二個參數5
指明切片的長度,第三個參數8
指明切片的容量。索引
切片的容量是什麼意思呢? 還記得上面說的嗎:數組是切片的底層數據結構的一部分。切片的容量實際上表明瞭它的底層數組的長度。 在切片s1上應用切片表達式,獲得的新的切片s2的底層數組和s1的底層數組是同樣的。string
一旦一個切片沒法容納更多的元素,Go語言就會想辦法擴容。可是它並不會改變原來的切片,而是會生成一個容量更大的切片,而後把原有的元素和新元素一併拷貝到新的切片總。在通常狀況下,能夠簡單地認爲新切片的容量(簡稱新容量)將會是原切片容量(簡稱原容量)的2倍。
可是當原切片的長度(原長度)大於或等於1024時,Go語言將會以原容量的1.25倍做爲新容量的基準(新容量基準)。新容量基準將會被調整(不斷地與1.25相乘),直到結果不小於原長度與要追加的元素數量之和(簡稱新長度)。最終,新容量每每會比新長度大一些,固然,相等也是可能的。
另外,若是咱們一次追加的元素過多,以致於新長度比原容量的2倍還要大,那麼新容量就會以新長度爲基準。與前面的狀況同樣,最終的容量在不少時候都要比新容量基準更大一些。
確切的說,一個切片的底層數組永遠不會被替換。爲何?雖然在擴容的時候,Go語言必定會生成新的底層數組,可是它同時也生成了新的切片。它是把新的切片做爲了新底層數組的窗口,而沒有對原切片及其底層數組作任何改動。
請記住,在無需擴容的時候,append函數返回的是指向原底層數組的新切片,而在須要擴容的時候,append函數返回的是指向新底層數組的新切片。因此,嚴格來說,「擴容」這個詞用在這裏雖然形象可是不合適。
只要新長度不會超過原切片的原容量,那麼使用append函數對其追加元素的時候就不會引發擴容。這隻會使緊鄰切片窗口右邊(底層數組中的)元素被新的元素替換掉。
初始時兩個切片引用同一個底層數組,在後續操做中對某個切片的操做超出底層數組的容量時,這兩個切片引用的就不是同一個數組了
s1 :=[]int{1,2,3,4} s2 := s1[0:4] 就像這樣,這樣的話改變s2會影響s1,如何消除這種影響呢
能夠用copy函數,或者本身深拷貝。
切片縮容以後仍是會引用底層的原數組,這有時候會形成大量縮容以後的多餘內容沒有被垃圾回收。可使用新建一個數組而後copy的方式。