在 Golang 中,陣列 Arrays
與切片 Slices
是最基本的資料結構之一。兩者有相似的地方,但切片比陣列更加靈活且高效,通常在開發中更推薦使用切片。本文將介紹陣列與切片的基礎語法,並探討切片的容量管理與應用場景。
在 Golang 中,陣列是固定大小
的資料集合,一旦宣告,大小就無法改變
。陣列中的每個元素都有一個固定的記憶體位置
。
var arr [5]int // 宣告一個大小為 5 的整數陣列
arr[0] = 10 // 為陣列的第一個元素賦值
fmt.Println(arr)
這段程式碼建立了一個大小為 5 的整數陣列 arr,並將第一個元素設為 10。
import (
"fmt"
)
func main() {
arr := [3]int{1, 2, 3}
fmt.Printf("arr[0] 的位址: %p\n", &arr[0])
fmt.Printf("arr[1] 的位址: %p\n", &arr[1])
fmt.Printf("arr[2] 的位址: %p\n", &arr[2])
}
</* Output: */>
arr[0] 的位址: 0x140000160c0
arr[1] 的位址: 0x140000160c8
arr[2] 的位址: 0x140000160d0
(小提示:如果自行實作時,顯示的位址可能會和我上面的例子有所不同,屬於正常現象。)
切片與陣列不同,切片的大小是動態的
,可以根據需要增長或縮減
。切片是 Golang 中更推薦使用的資料結構,因為它更靈活且有效率。
nums := []int{1, 2, 3, 4, 5} // 宣告一個切片
fmt.Println(nums)
make()
建立切片:make()
是 Golang 中用來建立切片的函數,我們可以指定切片的長度和容量。
nums := make([]int, 3, 5) // 建立一個長度為 3,容量為 5 的切片
nums[0] = 10
fmt.Println(nums) // 輸出:[10 0 0]
這裡的切片
nums
長度是 3,表示有 3 個元素可供使用,容量為 5,表示它最多可以容納 5 個元素而不需要重新分配記憶體。
為什麼推薦使用切片?
make()
?在 Golang 中,make()
函數是一個用來初始化特定類型的內建函數,主要用於創建切片(slices)
、字典(maps)
和通道(channels)
。這三種資料結構是基於引用的資料結構,無法像其他類型一樣通過簡單的變量宣告來使用,因此需要通過 make() 來進行初始化。
make()
:專門用於創建切片、字典和通道,並且進行初始化,返回具備完整操作能力的資料結構。
new()
:用來為任何類型分配內存,返回該類型的指針,但不進行初始化。new()
返回的指針需要手動初始化才能使用。(指針的使用會在第12天
做更為詳細的介紹!)
比較:
p := new([]int) // 返回的是切片的指針,需要初始化才能使用
*p = make([]int, 5) // 這裡才進行了初始化
fmt.Println(*p) // 輸出:[0 0 0 0 0]
q := make([]int, 5) // 直接使用 make() 創建並初始化
fmt.Println(q) // 輸出:[0 0 0 0 0]
當切片的大小超過其容量時,Golang 會自動分配一個新的、容量更大的底層陣列,並將舊切片的數據複製到新陣列中。這個過程可能導致性能問題,特別是當處理大量數據時。
nums := make([]int, 3, 5) // 建立長度為 3、容量為 5 的切片
fmt.Printf("長度: %d, 容量: %d\n", len(nums), cap(nums))
nums = append(nums, 4, 5, 6) // 添加三個元素,超過原始容量
fmt.Printf("長度: %d, 容量: %d\n", len(nums), cap(nums)) // 新容量會擴增
</* Output: */>
長度: 3, 容量: 5
長度: 6, 容量: 10
這裡展示了當切片超過其初始容量時,Golang 會自動擴展切片的容量。
內存複製
是指將資料從一個記憶體位置複製到另一個記憶體位置的過程。在程式執行過程中,內存複製通常發生在你需要將資料從一個地方複製到另一個地方時,例如擴展陣列或切片時的操作。
像是上面的例子,由於原來的容量不足以容納新元素,Golang 會自動分配一塊新的、更大的記憶體區域(通常是原來容量的兩倍),然後將原來的數據 1, 2 複製到新的區域,再把新元素 3 加進去。這個過程就是
內存複製
。
每次執行內存複製都會消耗 CPU 和記憶體資源,特別是在處理大量資料時,頻繁的內存複製會導致程式性能下降。
在處理大量數據時,應避免頻繁的內存重分配。可以通過預先分配足夠的容量來減少內存複製。
nums := make([]int, 0, 1000) // 預先分配容量 1000
for i := 0; i < 1000; i++ {
nums = append(nums, i)
}
fmt.Println("容量:", cap(nums)) // 確保沒有多餘的內存分配
這樣可以確保在迴圈中不會過度擴展切片,減少內存分配的開銷。
今天我們學到了 Golang 中 陣列與切片 的基礎語法。陣列是固定大小的,而切片則更靈活,能夠動態增長。切片是更推薦的資料結構,並且可以透過 make()
來管理切片的長度與容量。我們也探討了如何避免頻繁的內存複製,以提升程式效能,並強調了在處理大量數據時,預先分配足夠的容量是非常重要的。