Go 語言中的動態陣列:深入解析切片

更新於 2023/08/31閱讀時間約 9 分鐘


raw-image

👨‍💻簡介

在 Go 語言中,切片(Slice)是一種動態序列的資料結構,能夠方便地存儲和操作多個相同類型的元素。切片相比於陣列,更具有彈性,因為它的大小是可變的,可以根據需要動態增長或縮小。切片在處理集合型資料時非常實用,讓你能夠輕鬆地新增、刪除、修改和操作元素,同時避免了固定大小的限制。

切片的基本概念

切片是由一個指向陣列的指針、切片長度和切片容量組成的。切片的長度指的是切片中實際包含的元素個數,而切片的容量則是從切片開始的底層陣列中能夠訪問的元素個數。切片的容量可以大於或等於切片的長度。

宣告和初始化切片

在 Go 中,宣告和初始化切片可以使用以下的語法:

var slice1 []int                     // 創建一個整數切片,大小和容量都是 0
slice2 := []string{"A", "B", "C"} // 創建一個包含三個字串元素的切片
slice3 := make([]int, 5) // 創建一個整數切片,大小為 5,容量也為 5
slice4 := make([]int, 3, 5) // 創建一個整數切片,大小為 3,容量為 5

切片的基本操作

新增元素到切片

Go語言中有個內件函式append(),可以用來新增元素到切片中,這使得切片能夠根據需求動態增長。

numbers := []int{10, 20, 30}
numbers = append(numbers, 40, 50) // 新增兩個元素到切片

需要注意的是,如果切片的容量不足以容納新增的元素,append() 函式會創建一個新的切片,並將舊的元素和新的元素一同複製到新的切片中。

查詢和修改切片元素

切片的元素可以通過索引來存取,索引從 0 開始計數。

numbers := []int{10, 20, 30, 40, 50}
firstNumber := numbers[0] // 存取第一個元素,值為 10
secondNumber := numbers[1] // 存取第二個元素,值為 20
numbers[2] = 35 // 修改切片中的元素,將第三個元素改為 35

切割和遍歷切片

可以使用切片的切割操作來獲取部分切片,這可以通過指定切片的起始索引和結束索引來實現:

numbers := []int{10, 20, 30, 40, 50}
subSlice := numbers[1:4] // 從第二個元素到第四個元素的子切片,值為 [20 30 40]
  • [:]:使用 [:] 語法可以獲得完整的切片,即包含所有元素的切片。
  • [x:]:這種語法表示從索引 x 開始,提取所有直到切片結尾的元素。
  • [:x]:這種語法表示提取從開頭到索引 x-1 的元素,不包含索引 x 的元素。

切片的遍歷可以使用傳統的索引方式,或者使用 range 來簡化遍歷過程。

numbers := []int{10, 20, 30, 40, 50}

// 使用傳統的索引方式遍歷切片
for i := 0; i < len(numbers); i++ {
fmt.Println(numbers[i])
}
// 使用 range 遍歷切片
for index, value := range numbers {
fmt.Printf("索引:%d,值:%d\n", index, value)
}
for i := range numbers {
fmt.Println(numbers[i])
}

刪除切片元素

雖然切片沒有內建的刪除方法,不過可以使用切片的切割操作,將不需要的元素排除在外。

slice := []int{10, 20, 30, 40, 50}
indexToDelete := 2
slice = append(slice[:indexToDelete], slice[indexToDelete+1:]...) // 刪除索引 2 的元素

切片的容量

切片的容量就是指,你從切片開始的位置能夠往後訪問到的元素數量。當你在切片上進行新增元素的操作時,如果新加進來的元素數量超過了切片目前的容量,Go 語言會做一些事情:它會重新搞一個更大的陣列,然後把舊的元素都複製到這個新陣列中。這個過程會花一些時間,也就是所謂的性能開銷。

package main

import "fmt"
func main() {
numbers := []int{1, 2, 3}
fmt.Println("長度:", len(numbers)) // 輸出:長度:3
fmt.Println("容量:", cap(numbers)) // 輸出:容量:3
slice := numbers[1:2]
fmt.Println("切片:", slice) // 輸出:切片:[2]
fmt.Println("切片長度:", len(slice)) // 輸出:切片長度:1
fmt.Println("切片容量:", cap(slice)) // 輸出:切片容量:2
// 切片的容量是從切片的起始索引開始計算,一直到底層陣列的末尾索引。因此容量為2
// 新增元素超過切片容量時,會自動擴容並分配更大的底層陣列
slice = append(numbers, 4) // 新切片為 [1, 2, 3, 4]
fmt.Println("切片:", slice) // 輸出:切片:[1 2 3 4]
fmt.Println("切片長度:", len(slice)) // 輸出:切片長度:4
fmt.Println("切片容量:", cap(slice)) // 輸出:切片容量:6
}

切片的特性、限制與使用場景

切片的特性

  • 切片的大小是動態的,可以隨時進行增長或縮小。
  • 切片可以方便地從現有的陣列或切片中創建,不需要顯式地指定容量。
  • 切片的新增、刪除、修改操作都非常方便,讓你能夠輕鬆地操作集合型資料。
  • 切片的背後通常使用動態陣列來實現,因此在內存佈局上更具彈性,不受固定大小的限制。
  • 切片是引用類型,這意味著它們引用底層的陣列,而不是複製數據。當你將一個切片賦值給另一個切片,它們實際上共享同一份數據。因此,對其中一個切片所做的修改將影響到另一個切片。 以下是一個實際案例:
slice1 := []int{1, 2, 3}
slice2 := slice1
slice2[0] = 3
fmt.Println(slice1, slice2) // 輸出:[3 2 3] [3 2 3]

在這裡,修改 slice2 的值同樣影響了 slice1,因為它們引用同一份底層數據。這是切片和陣列之間的一個重要區別。

切片的限制

  • 記憶體配置: 切片的內部實現中使用了底層的陣列,因此切片所佔用的記憶體空間可能比實際所需大。當切片的元素數量增加時,Go 語言可能會重新配置更大的陣列,導致一些性能開銷。
  • 不適用於大型資料: 對於大型資料集合,切片可能不是最佳選擇。大型切片可能導致記憶體占用過多,影響程式的效能。
  • 不支援多維切片: 切片僅支援一維結構,如果需要處理多維資料,可能需要自行實現多維切片的概念。

使用場景

  • 動態資料集合: 切片的大小是可變的,使其非常適用於處理動態資料集合,無需事先知道集合的大小。
  • API 請求和回應: 在處理 API 請求和回應時,切片可用於儲存和解析不確定數量的請求參數或回應資料。
  • 資料過濾和轉換: 使用 range 遍歷切片,可以輕鬆地過濾或轉換切片中的元素,進行處理和計算。
  • 傳遞函式參數: 切片的引用類型特性使其適用於傳遞函式參數,避免不必要的資料複製。
  • 檔案讀寫: 切片可用於讀取大量數據,進行處理後再寫回檔案。
  • 實現堆疊和佇列: 使用切片可以實現簡單的堆疊(後進先出)和佇列(先進先出)結構。
  • 排序和搜尋: 切片在排序和搜尋資料時非常有用,可以利用 sort 套件進行排序,並使用二分搜尋等技術進行搜尋。

常見用法

  • 資料過濾和轉換
// 將切片中的所有元素乘以 2
numbers := []int{1, 2, 3, 4, 5}
for i := range numbers {
numbers[i] *= 2
}

// 過濾出大於 3 的元素
filteredNumbers := []int{}
for _, num := range numbers {
if num > 3 {
filteredNumbers = append(filteredNumbers, num)
}
}
  • 傳遞函式參數
func modifySlice(slice []int) {
slice[0] = 100
}

numbers := []int{1, 2, 3}
modifySlice(numbers)

小結

切片是 Go 語言中非常實用的資料結構,它解決了陣列大小固定的限制,讓你能夠輕鬆地處理動態大小的集合型資料。切片的操作包括取得、修改、新增、刪除等,讓你可以靈活地處理資料集合。

在遍歷切片時,range 很方便地提供了索引和值,讓你能夠輕鬆地訪問切片中的元素。切片的特性和優勢使得它在處理動態數據集合時成為 Go 程式設計中的一個重要工具。

📚Reference

avatar-img
17會員
83內容數
golang
留言0
查看全部
avatar-img
發表第一個留言支持創作者!
Alan的開發者天地 的其他內容
👨‍💻簡介 陣列就像是一個儲存相同類型資料的容器,你可以想像成裝滿了一樣東西的盒子,每個東西都叫做陣列元素。這種類型可以是基本的,像是整數或字串,也可以是你自己定義的型別。不過陣列有個限制,就是大小一旦確定就無法改變。在Go語言裡,陣列的長度也是型別的一部分。
👨‍💻簡介 本文簡單介紹了 Go 語言的流程控制概念,涵蓋了從條件語句到迴圈,再到 range 遍歷數據結構,以及 goto 與標籤 label 的應用。主要知識點為如何使用 if 語句進行條件判斷,以及在不同情況下運用 switch 語句。
👨‍💻簡介 本文快速介紹了 Go 語言中的各種運算符,從數學計算到邏輯判斷,包括自增自減、賦值、比較和位運算。透過實例和清晰的解釋,快速掌握如何在程式中運用這些運算符。
👨‍💻簡介 Go 語言有各種資料型別,分為基本型別和複合型別。基本型別包括: 整數、浮點數、布林值、字串 複合型別包括: 陣列、片段、結構、函式、對映、通道、介面 等。 整數型別 整數型別有許多種,像是 int8、int16、int32、int64。我們可以依據實際需求選擇。
👨‍💻簡介 在 Golang 中,你可以使用不同的方式來宣告變數和常數。宣告變數時,可以直接指定值,或者使用型別推導,更簡單地用 := 來宣告局部變數。另外,還可以一次宣告多個變數,相同型別的變數可以一起宣告,或者使用括號宣告不同型別的變數。常數則使用 const 關鍵字宣告,確保值不變
👨‍💻簡介 在這篇文章裡,會簡單介紹幾個關鍵的基本概念和語法結構,加快上手這門程式語言。
👨‍💻簡介 陣列就像是一個儲存相同類型資料的容器,你可以想像成裝滿了一樣東西的盒子,每個東西都叫做陣列元素。這種類型可以是基本的,像是整數或字串,也可以是你自己定義的型別。不過陣列有個限制,就是大小一旦確定就無法改變。在Go語言裡,陣列的長度也是型別的一部分。
👨‍💻簡介 本文簡單介紹了 Go 語言的流程控制概念,涵蓋了從條件語句到迴圈,再到 range 遍歷數據結構,以及 goto 與標籤 label 的應用。主要知識點為如何使用 if 語句進行條件判斷,以及在不同情況下運用 switch 語句。
👨‍💻簡介 本文快速介紹了 Go 語言中的各種運算符,從數學計算到邏輯判斷,包括自增自減、賦值、比較和位運算。透過實例和清晰的解釋,快速掌握如何在程式中運用這些運算符。
👨‍💻簡介 Go 語言有各種資料型別,分為基本型別和複合型別。基本型別包括: 整數、浮點數、布林值、字串 複合型別包括: 陣列、片段、結構、函式、對映、通道、介面 等。 整數型別 整數型別有許多種,像是 int8、int16、int32、int64。我們可以依據實際需求選擇。
👨‍💻簡介 在 Golang 中,你可以使用不同的方式來宣告變數和常數。宣告變數時,可以直接指定值,或者使用型別推導,更簡單地用 := 來宣告局部變數。另外,還可以一次宣告多個變數,相同型別的變數可以一起宣告,或者使用括號宣告不同型別的變數。常數則使用 const 關鍵字宣告,確保值不變
👨‍💻簡介 在這篇文章裡,會簡單介紹幾個關鍵的基本概念和語法結構,加快上手這門程式語言。
你可能也想看
Google News 追蹤
Thumbnail
*合作聲明與警語: 本文係由國泰世華銀行邀稿。 證券服務係由國泰世華銀行辦理共同行銷證券經紀開戶業務,定期定額(股)服務由國泰綜合證券提供。   剛出社會的時候,很常在各種 Podcast 或 YouTube 甚至是在朋友間聊天,都會聽到各種市場動態、理財話題,像是:聯準會降息或是近期哪些科
Thumbnail
在進入主題之前建議先行閱讀「【程式語言 - Go】來認識Google開發的程式語言…」,初步認識一下Go語言是什麼? 容不容易學習? 才能夠更快的體會此篇章的目的。 當我們在進行軟體開發時,常常會需要有背後的資料庫系統來儲存我們的資料,而資料庫系統也會隨著時代的演進,進行大幅度的更新,那在這樣
Thumbnail
Golang(Go)是由Google開發的一種開源的、靜態型別的編程語言,目的在提供一個簡單、高效、安全以及易於擴展的程式語言,特別適用於並發和平行處理,Go語言設計上著重於開發者的生產力,並提供了現代化的語法和豐富的標準庫。 強調簡單易讀,讓我們回歸原始以最簡易的方式來撰寫程式,併發的特性讓日趨
Thumbnail
前言介紹 在 golang 1.16之後官方提供的工具包裡面有個 `embed` 可以使用,這使得把檔案嵌入 golang 的二進制編譯更為容易,以至於方便我們部署一些並非 .go 的副檔名檔案。 這裡要介紹的是如何把 vue 作為前端,編譯至我們的 golang 專案內,起一個網頁服務。 在開始
Thumbnail
由於Go語言本身沒有提供Enum的功能, 故我們可以使用package及type的技巧來達到類似的功能,假設今天要定義季節的enum型別, 包含了「春、夏、秋、冬」四種值的時候,可以怎麼做呢? 首先我們可以用package來框住season的範圍: 然而在season.go可以定義一個字串的類型 最
Thumbnail
(2022年2月21日,台北訊)2月對訓練家們是一個忙碌的月份,「Pokémon GO Tour:城都地區」將於2022年2月26日(星期六)9:00~21:00( 當日時間 )舉辦,緊接著隔天2月27日(星期天)更在高雄舉行全世界唯二的「Pokémon GO Tour:Live」實體活動!
Thumbnail
英國作者在一篇投稿中感嘆 小鎮(town)裡的五金雜貨店(hardware shops)都消失了, 他說: "Hardware shops in any small towns have gone the way of the dinosaurs."
Thumbnail
完整標題:go on 與「繼往走向」或「繼往開來」及「繼」、「續」、「繼續」、「接續」、「启開」、「正昂」、「發生」等的轉換密碼
Thumbnail
完整標題:go 與「之」、「至」、「至于」、「到」、「到于」、「前往」、「進往」、「步往」、「走」、「走于」、「走往」、「行」、「行于」、「行往」、「行走」、「去」、「過」、「過去」、「過于」、「步」、「步于」、「步往」、「步行」、「機遇」、「行旺」等的轉換密碼
Thumbnail
完整標題:go around 與「逛」、「觀覽」、「交往」、「相處」、「走訪」、「轉繞圓動」等的轉換密碼及「天狼星」之謎
Thumbnail
*合作聲明與警語: 本文係由國泰世華銀行邀稿。 證券服務係由國泰世華銀行辦理共同行銷證券經紀開戶業務,定期定額(股)服務由國泰綜合證券提供。   剛出社會的時候,很常在各種 Podcast 或 YouTube 甚至是在朋友間聊天,都會聽到各種市場動態、理財話題,像是:聯準會降息或是近期哪些科
Thumbnail
在進入主題之前建議先行閱讀「【程式語言 - Go】來認識Google開發的程式語言…」,初步認識一下Go語言是什麼? 容不容易學習? 才能夠更快的體會此篇章的目的。 當我們在進行軟體開發時,常常會需要有背後的資料庫系統來儲存我們的資料,而資料庫系統也會隨著時代的演進,進行大幅度的更新,那在這樣
Thumbnail
Golang(Go)是由Google開發的一種開源的、靜態型別的編程語言,目的在提供一個簡單、高效、安全以及易於擴展的程式語言,特別適用於並發和平行處理,Go語言設計上著重於開發者的生產力,並提供了現代化的語法和豐富的標準庫。 強調簡單易讀,讓我們回歸原始以最簡易的方式來撰寫程式,併發的特性讓日趨
Thumbnail
前言介紹 在 golang 1.16之後官方提供的工具包裡面有個 `embed` 可以使用,這使得把檔案嵌入 golang 的二進制編譯更為容易,以至於方便我們部署一些並非 .go 的副檔名檔案。 這裡要介紹的是如何把 vue 作為前端,編譯至我們的 golang 專案內,起一個網頁服務。 在開始
Thumbnail
由於Go語言本身沒有提供Enum的功能, 故我們可以使用package及type的技巧來達到類似的功能,假設今天要定義季節的enum型別, 包含了「春、夏、秋、冬」四種值的時候,可以怎麼做呢? 首先我們可以用package來框住season的範圍: 然而在season.go可以定義一個字串的類型 最
Thumbnail
(2022年2月21日,台北訊)2月對訓練家們是一個忙碌的月份,「Pokémon GO Tour:城都地區」將於2022年2月26日(星期六)9:00~21:00( 當日時間 )舉辦,緊接著隔天2月27日(星期天)更在高雄舉行全世界唯二的「Pokémon GO Tour:Live」實體活動!
Thumbnail
英國作者在一篇投稿中感嘆 小鎮(town)裡的五金雜貨店(hardware shops)都消失了, 他說: "Hardware shops in any small towns have gone the way of the dinosaurs."
Thumbnail
完整標題:go on 與「繼往走向」或「繼往開來」及「繼」、「續」、「繼續」、「接續」、「启開」、「正昂」、「發生」等的轉換密碼
Thumbnail
完整標題:go 與「之」、「至」、「至于」、「到」、「到于」、「前往」、「進往」、「步往」、「走」、「走于」、「走往」、「行」、「行于」、「行往」、「行走」、「去」、「過」、「過去」、「過于」、「步」、「步于」、「步往」、「步行」、「機遇」、「行旺」等的轉換密碼
Thumbnail
完整標題:go around 與「逛」、「觀覽」、「交往」、「相處」、「走訪」、「轉繞圓動」等的轉換密碼及「天狼星」之謎