大家好,我是碼農先森。
陣列與切片的區別
在 Go 語言中,陣列和切片是兩種不同的資料結構,它們之間有以下主要區別。
引數長度:
陣列(Array):陣列的長度是固定的,在建立時就需要指定陣列的長度,無法動態改變;只有長度資訊,透過 len()
函式獲取。
切片(Slice):切片是對陣列的一個引用,底層使用的是陣列的資料結構,具有動態長度,可以動態增加或減少元素,實現動態擴容;有長度和容量資訊,透過 len()
和 cap()
函式可以獲取。
引數傳遞:
陣列:在函式間傳遞陣列會進行值複製,較大的陣列會導致效能開銷。
切片:切片是對底層陣列的引用,傳遞切片時只是傳遞引用,並不會複製整個陣列,節省記憶體和效能。
切片的擴容
當一個切片透過切片操作(如 append
、copy
、slicing
等)對底層陣列進行修改時,如果底層陣列容量不足,會建立一個新的底層陣列,並將資料複製到新的底層陣列中,此時切片會指向新的底層陣列。
追加一個元素時,如果切片的容量能夠容納新增元素,即切片的長度小於容量,那麼切片的長度會增加 1,容量不變。
但如果超出了當前容量,即切片的長度等於容量,那麼會觸發切片的擴容,根據倍增規則重新分配底層陣列,當原切片的長度大於或等於 1024 時,會以原容量的 1.25 倍作為新容量的基準;透過下面的例子和圖解可以更加具體的瞭解擴容的過程。
// 長度與容量相等
func TestSlice(t *testing.T) {
var a []int
fmt.Printf("%v, %v\n", len(a), cap(a)) // 0, 0
a = append(a, 1)
a = append(a, 2)
fmt.Printf("%v, %v\n", len(a), cap(a)) // 2, 2
}
// 當元素的個數超過 1024 長度,則會以 (1280 / 1025) = 1.25 倍進行擴容
func TestSlice(t *testing.T) {
var a []int
fmt.Printf("%v, %v\n", len(a), cap(a)) // 0, 0
i := 1
for i <= 1025 {
a = append(a, i)
i += 1
}
fmt.Printf("%v, %v\n", len(a), cap(a)) // 1025, 1280
}
總結
我們瞭解了陣列和切片之間的關係。切片是基於陣列的,可變長的,並且操作快。一個切片的容量總是固定的,而且一個切片也只會與某一個底層陣列關聯。切片的擴容是根據倍增規則重新分配了底層的陣列,如果頻繁的動態擴容,可能會帶來一些效能開銷。因此,在對效能有嚴格要求的場景下,儘量提前估算切片所需的容量,避免頻繁的動態擴容。
歡迎關注、分享、點贊、收藏、在看,我是碼農先森。