Go 語言學習筆記之陣列與切片

Yxh_blogs發表於2024-06-03

大家好,我是碼農先森。

陣列與切片的區別

在 Go 語言中,陣列和切片是兩種不同的資料結構,它們之間有以下主要區別。

引數長度:
陣列(Array):陣列的長度是固定的,在建立時就需要指定陣列的長度,無法動態改變;只有長度資訊,透過 len() 函式獲取。
切片(Slice):切片是對陣列的一個引用,底層使用的是陣列的資料結構,具有動態長度,可以動態增加或減少元素,實現動態擴容;有長度和容量資訊,透過 len()cap() 函式可以獲取。

引數傳遞:
陣列:在函式間傳遞陣列會進行值複製,較大的陣列會導致效能開銷。
切片:切片是對底層陣列的引用,傳遞切片時只是傳遞引用,並不會複製整個陣列,節省記憶體和效能。

切片的擴容

當一個切片透過切片操作(如 appendcopyslicing 等)對底層陣列進行修改時,如果底層陣列容量不足,會建立一個新的底層陣列,並將資料複製到新的底層陣列中,此時切片會指向新的底層陣列。

追加一個元素時,如果切片的容量能夠容納新增元素,即切片的長度小於容量,那麼切片的長度會增加 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
}

總結

我們瞭解了陣列和切片之間的關係。切片是基於陣列的,可變長的,並且操作快。一個切片的容量總是固定的,而且一個切片也只會與某一個底層陣列關聯。切片的擴容是根據倍增規則重新分配了底層的陣列,如果頻繁的動態擴容,可能會帶來一些效能開銷。因此,在對效能有嚴格要求的場景下,儘量提前估算切片所需的容量,避免頻繁的動態擴容。

歡迎關注、分享、點贊、收藏、在看,我是碼農先森。

相關文章