大家好,我是碼農先森。 數組與切片的區別 在 Go 語言中,數組和切片是兩種不同的數據結構,它們之間有以下主要區別。 參數長度: 數組(Array):數組的長度是固定的,在創建時就需要指定數組的長度,無法動態改變;只有長度信息,通過 len() 函數獲取。 切片(Slice):切片是對數組的一個引用 ...
大家好,我是碼農先森。
數組與切片的區別
在 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
}
總結
我們瞭解了數組和切片之間的關係。切片是基於數組的,可變長的,並且操作快。一個切片的容量總是固定的,而且一個切片也只會與某一個底層數組關聯。切片的擴容是根據倍增規則重新分配了底層的數組,如果頻繁的動態擴容,可能會帶來一些性能開銷。因此,在對性能有嚴格要求的場景下,儘量提前估算切片所需的容量,避免頻繁的動態擴容。
歡迎關註、分享、點贊、收藏、在看,我是碼農先森。