golang中切片是啥

2022-11-24 22:01:39

在golang中,切片是對陣列的一個連續片段的參照,這個片段可以是整個陣列,也可以是由起始和終止索引標識的一些項的子集。Go語言中切片的內部結構包含地址、大小和容量,切片一般用於快速地操作一塊資料集合,如果將資料集合比作切糕的話,切片就是你要的「那一塊」,切的過程包含從哪裡開始(切片的起始位置)及切多大(切片的大小),容量可以理解為裝切片的口袋大小。

php入門到就業線上直播課:進入學習
Apipost = Postman + Swagger + Mock + Jmeter 超好用的API偵錯工具:

本教學操作環境:windows7系統、GO 1.18版本、Dell G3電腦。

切片(slice)是對陣列的一個連續片段的參照,所以切片是一個參照型別(因此更類似於 C/C++ 中的陣列型別,或者 Python 中的 list 型別),這個片段可以是整個陣列,也可以是由起始和終止索引標識的一些項的子集,需要注意的是,終止索引標識的項不包括在切片內。

Go語言中切片的內部結構包含地址、大小和容量,切片一般用於快速地操作一塊資料集合,如果將資料集合比作切糕的話,切片就是你要的「那一塊」,切的過程包含從哪裡開始(切片的起始位置)及切多大(切片的大小),容量可以理解為裝切片的口袋大小,如下圖所示。

1.jpg
圖:切片結構和記憶體分配

從陣列或切片生成新的切片

切片預設指向一段連續記憶體區域,可以是陣列,也可以是切片本身。

從連續記憶體區域生成切片是常見的操作,格式如下:

slice [開始位置 : 結束位置]
登入後複製

語法說明如下:

  • slice:表示目標切片物件;

  • 開始位置:對應目標切片物件的索引;

  • 結束位置:對應目標切片的結束索引。

從陣列生成切片,程式碼如下:

var a  = [3]int{1, 2, 3}
fmt.Println(a, a[1:2])
登入後複製

其中 a 是一個擁有 3 個整型元素的陣列,被初始化為數值 1 到 3,使用 a[1:2] 可以生成一個新的切片,程式碼執行結果如下:

[1 2 3]  [2]
登入後複製

其中 [2] 就是 a[1:2] 切片操作的結果。

從陣列或切片生成新的切片擁有如下特性:

  • 取出的元素數量為:結束位置 - 開始位置;

  • 取出元素不包含結束位置對應的索引,切片最後一個元素使用 slice[len(slice)] 獲取;

  • 當預設開始位置時,表示從連續區域開頭到結束位置;

  • 當預設結束位置時,表示從開始位置到整個連續區域末尾;

  • 兩者同時預設時,與切片本身等效;

  • 兩者同時為 0 時,等效於空切片,一般用於切片復位。

根據索引位置取切片 slice 元素值時,取值範圍是(0~len(slice)-1),超界會報執行時錯誤,生成切片時,結束位置可以填寫 len(slice) 但不會報錯。【相關推薦:Go視訊教學

下面通過範例來熟悉切片的特性。

1) 從指定範圍中生成切片

切片和陣列密不可分,如果將陣列理解為一棟辦公樓,那麼切片就是把不同的連續樓層出租給使用者,出租的過程需要選擇開始樓層和結束樓層,這個過程就會生成切片,範例程式碼如下:

var highRiseBuilding [30]int
for i := 0; i < 30; i++ {
        highRiseBuilding[i] = i + 1
}
// 區間
fmt.Println(highRiseBuilding[10:15])
// 中間到尾部的所有元素
fmt.Println(highRiseBuilding[20:])
// 開頭到中間指定位置的所有元素
fmt.Println(highRiseBuilding[:2])
登入後複製

程式碼輸出如下:

2.png

程式碼中構建了一個 30 層的高層建築,陣列的元素值從 1 到 30,分別代表不同的獨立樓層,輸出的結果是不同的租售方案。

程式碼說明如下:

  • 第 8 行,嘗試出租一個區間樓層。

  • 第 11 行,出租 20 層以上。

  • 第 14 行,出租 2 層以下,一般是商用鋪面。

切片有點像C語言裡的指標,指標可以做運算,但代價是記憶體操作越界,切片在指標的基礎上增加了大小,約束了切片對應的記憶體區域,切片使用中無法對切片內部的地址和大小進行手動調整,因此切片比指標更安全、強大。

2) 表示原有的切片

生成切片的格式中,當開始和結束位置都被忽略時,生成的切片將表示和原切片一致的切片,並且生成的切片與原切片在資料內容上也是一致的,程式碼如下:

a := []int{1, 2, 3}
fmt.Println(a[:])
登入後複製

a 是一個擁有 3 個元素的切片,將 a 切片使用 a[:] 進行操作後,得到的切片與 a 切片一致,程式碼輸出如下:

3.png

3) 重置切片,清空擁有的元素

把切片的開始和結束位置都設為 0 時,生成的切片將變空,程式碼如下:

a := []int{1, 2, 3}
fmt.Println(a[0:0])
登入後複製

程式碼輸出如下:

4.png

直接宣告新的切片

除了可以從原有的陣列或者切片中生成切片外,也可以宣告一個新的切片,每一種型別都可以擁有其切片型別,表示多個相同型別元素的連續集合,因此切片型別也可以被宣告,切片型別宣告格式如下:

var name []Type
登入後複製

其中 name 表示切片的變數名,Type 表示切片對應的元素型別。

下面程式碼展示了切片宣告的使用過程:

// 宣告字串切片
var strList []string
// 宣告整型切片
var numList []int
// 宣告一個空切片
var numListEmpty = []int{}
// 輸出3個切片
fmt.Println(strList, numList, numListEmpty)
// 輸出3個切片大小
fmt.Println(len(strList), len(numList), len(numListEmpty))
// 切片判定空的結果
fmt.Println(strList == nil)
fmt.Println(numList == nil)
fmt.Println(numListEmpty == nil)
登入後複製

程式碼輸出結果:

5.png

程式碼說明如下:

  • 第 2 行,宣告一個字串切片,切片中擁有多個字串。

  • 第 5 行,宣告一個整型切片,切片中擁有多個整型數值。

  • 第 8 行,將 numListEmpty 宣告為一個整型切片,本來會在{}中填充切片的初始化元素,這裡沒有填充,所以切片是空的,但是此時的 numListEmpty 已經被分配了記憶體,只是還沒有元素。

  • 第 11 行,切片均沒有任何元素,3 個切片輸出元素內容均為空。

  • 第 14 行,沒有對切片進行任何操作,strList 和 numList 沒有指向任何陣列或者其他切片。

  • 第 17 行和第 18 行,宣告但未使用的切片的預設值是 nil,strList 和 numList 也是 nil,所以和 nil 比較的結果是 true。

  • 第 19 行,numListEmpty 已經被分配到了記憶體,但沒有元素,因此和 nil 比較時是 false。

切片是動態結構,只能與 nil 判定相等,不能互相判定相等。宣告新的切片後,可以使用 append() 函數向切片中新增元素。

使用 make() 函數構造切片

如果需要動態地建立一個切片,可以使用 make() 內建函數,格式如下:

make( []Type, size, cap )
登入後複製

其中 Type 是指切片的元素型別,size 指的是為這個型別分配多少個元素,cap 為預分配的元素數量,這個值設定後不影響 size,只是能提前分配空間,降低多次分配空間造成的效能問題。

範例如下:

a := make([]int, 2)
b := make([]int, 2, 10)

fmt.Println(a, b)
fmt.Println(len(a), len(b))
登入後複製

程式碼輸出如下:

6.png

其中 a 和 b 均是預分配 2 個元素的切片,只是 b 的內部儲存空間已經分配了 10 個,但實際使用了 2 個元素。

容量不會影響當前的元素個數,因此 a 和 b 取 len 都是 2。

溫馨提示

使用 make() 函數生成的切片一定發生了記憶體分配操作,但給定開始與結束位置(包括切片復位)的切片只是將新的切片結構指向已經分配好的記憶體區域,設定開始與結束位置,不會發生記憶體分配操作。

更多程式設計相關知識,請存取:!!

以上就是golang中切片是啥的詳細內容,更多請關注TW511.COM其它相關文章!