- 原文地址:www.sohamkamani.com/blog/golang…
- 原文做者:Soham Kamani
- 譯文地址:github.com/watermelo/d…
- 譯者:咔嘰咔嘰
- 譯者水平有限,若有翻譯或理解謬誤,煩請幫忙指出
首先,很容易看到數組和切片好像是同一個東西:表示列表的數據結構。然而,它們實際上彼此徹底不一樣。git
在這篇文章中,咱們將探討他們在 Go 中的差別和實現。github
數組是固定的數據列表。這裏的重點是固定的,由於一旦設置了數組的長度,它就沒法更改。golang
咱們舉一個聲明瞭四個整數的數組的例子:數組
arr := [4]int{3, 2, 5, 4}
複製代碼
咱們在上面的例子中定義的 arr
變量的類型是 [4] int
,它是一個大小爲 4 的數組。這裏須要注意的是,4
包含在類型定義中。數據結構
這意味着兩個不一樣長度的數組其實是兩個不一樣的類型。因此不能將不一樣長度的數組視爲一種類型,也不能將其中一個的值分配給另外一個:app
longerArr := [5]int{5, 7, 1, 2, 0}
longerArr = arr
// 會拋出編譯錯誤
longerArr == arr
// 會拋出編譯錯誤
複製代碼
我發現考慮數組的一個好方法就是結構體。若是咱們能夠構造數組等價的結構體,它可能看起來像這樣:ide
// 長度爲 4 的數組的等價結構體
type int4 struct {
e0 int
e1 int
e2 int
e3 int
}
// 長度爲 5 的數組的等價結構體
type int5 struct {
e0 int
e1 int
e2 int
e3 int
e5 int
}
arr := int4{3, 2, 5, 4}
longerArr := int5{5, 7, 1, 2, 0}
複製代碼
不建議執行此操做,但這是一個很好的方法來了解爲什麼不一樣長度的數組是徹底不一樣的類型。函數
數組存儲爲指定類型的 n
塊的序列:post
初始化數組類型的變量後,將當即分配此內存。ui
在 Go 中,沒有引用傳遞。一切都是經過值傳遞的。若是將數組的值分配給另外一個變量,則會複製整個值。
若是隻想將「引用」傳遞給數組,可使用指針:
在內存分配和函數中,數組其實是一種很是簡單的數據類型,其工做方式與結構體相同。
咱們能夠將切片視爲基於數組的高級實現。
在 Go 中實現了切片,以涵蓋開發人員在處理列表時面臨的一些很是常見的需求,例如須要動態修改大小。
聲明切片幾乎與聲明數組相同,除了須要必須省略長度的說明符:
slice := []int{4, 5, 3}
複製代碼
僅僅看代碼的話,切片和數組看起來很是類似,但實際上在實現和使用方面存在顯著差別。
切片的分配方式與數組不一樣,其實是修改過的指針。每一個切片包含三條信息:
而後,能夠爲彼此的值分配不一樣長度的切片。它們的類型相同,指針,長度和容量都在變化:
slice1 := []int{6, 1, 2}
slice2 := []int{9, 3}
// 能夠將任何長度的切片分配給其餘切片
複製代碼
與數組不一樣,切片在初始化期間不分配數據塊的內存。實際上,切片用 nil
值初始化。
將切片分配給另外一個變量時,仍然按值傳遞。這裏的值僅指代指針,長度和容量,而不是元素自己佔用的內存。(譯者注:這裏作了一個實驗能夠更清晰地瞭解這個過程)
要向切片添加元素,一般使用 append
函數。
nums := []int{8, 0}
nums = append(nums, 8)
複製代碼
在內部,這會將指定的值分配給新元素,並返回一個新的切片。這個新切片的長度增長了 1。(譯者注:關於切片的擴容分析能夠參考煎魚和 stefno 的博客)
這就是爲何常常建議建立一個預先指定長度和容量的切片(特別是若是你很清楚它的大小多是多少):
arr := make([]int, 0, 5)
// 這將建立一個長度爲 0 且容量爲 5 的切片
複製代碼
數組和切片是徹底不一樣的,所以,它們的用例也是徹底不一樣的。
咱們來看一下開源項目和 Go 標準庫中的一些例子,看看它們怎麼使用的。
UUID 是 128 位數據,一般用來惟一標記對象或實體。一般以短劃線分隔的十六進制值表示:
e39bdaf4-710d-42ea-a29b-58c368b0c53c
複製代碼
在 Google 的 UUID 庫 中,UUID 表示爲 16 字節的數組:
type UUID [16]byte
複製代碼
這是有意義的,由於咱們知道 UUID 是由 128 位(16 字節)組成的。咱們不會在 UUID 中添加或刪除任何字節,所以使用數組來表示會更好。
在下一個示例中,咱們將查看排序標準庫中的 sort.Ints
函數:
s := []int{5, 2, 6, 3, 1, 4} // unsorted
sort.Ints(s)
fmt.Println(s)
// [1 2 3 4 5 6]
複製代碼
sort.Ints
函數接受一個整數列表並將它們排序。這裏選切片有兩個緣由:
如今咱們已經介紹了數組和切片之間的關鍵差別及其用例,這裏有一些提示能夠決定哪一種結構更合適:
咱們能夠看到,切片涵蓋了在 Go 中建立應用程序的大多數場景。儘管如此,數組確實有它們的位置,而且在須要它們時很是有用。
大家有更好的例子嗎?若是有任何關於你更喜歡切片勝於數組(反之亦然)的例子?請在下面的評論中告訴咱們👇