好吧,讓我們深入了解 Go 最通用和最重要的功能之一 - 切片。如果您來自另一種語言,您可能會認為切片與陣列類似。是的,它們確實有一些相似之處,但是切片帶來了更多的功能、靈活性和 Go 特有的魔力! ?
在 Go 中,切片是一種允許您處理元素列表(如數組)的類型,但它們是動態的,這意味著它們可以根據需要增長和縮小。無需像使用陣列那樣預先指定固定長度。它們背後有陣列支持,但你可以獲得更多的控制權。將它們視為數組更酷、更靈活的兄弟。
所以,Go 中的切片其實是底層陣列上的一個「視窗」。您可以透過增加或縮小該視窗來更改其大小,這就像切一塊蛋糕一樣順利。 ?
建立切片?
建立切片非常簡單:
// Using a literal numbers := []int{1, 2, 3, 4, 5} // Using the make function sliceOfStrings := make([]string, 5) // a slice of 5 strings, each
初始化為空字串
使用 make,您可以告訴 Go 建立一個特定長度的切片,但由它為您管理的陣列提供支援。所以你不需要擔心記憶體分配細節。 ?
切片中的兩個關鍵概念是長度和容量。長度是切片中目前元素的數量,而容量是在需要調整大小之前可以容納的元素總數。
numbers := []int{1, 2, 3} fmt.Println(len(numbers)) // 3 fmt.Println(cap(numbers)) // 3 (same as length here)
當您開始追加項目時,Go 會在填滿時將容量加倍,因此您不必擔心會達到上限。
numbers = append(numbers, 4) fmt.Println(len(numbers)) // 4 fmt.Println(cap(numbers)) // probably 6 now, depending on Go’s growth
圖案
附加到切片:Go 的內建魔法? ✨
使用 Go 的追加函數向切片添加元素就像做餡餅一樣簡單。您可以一次添加一個或多個元素,Go 將為您處理所有大小調整和記憶體操作。
numbers := []int{1, 2, 3} numbers = append(numbers, 4, 5, 6) // Adding multiple elements at once fmt.Println(numbers) // [1 2 3 4 5 6]
這種自動調整大小的功能使切片變得非常方便,尤其是當您不知道清單將有多大時。
Go 中的切片實際上是事情變得非常有趣的地方。您可以建立現有切片的“子切片”,而無需複製元素。
numbers := []int{10, 20, 30, 40, 50} subSlice := numbers[1:4] // Just takes a "slice" of the original slice fmt.Println(subSlice) // [20 30 40]
在數字[1:4]中,第一個索引(1)包含在內,最後一個索引(4)不包含。您最終會得到位於位置 1、2 和 3 的元素,但不是 4。
這個子切片仍然與原始切片共享相同的底層數組,因此對一個子切片的更改將影響另一個:
subSlice[0] = 25 fmt.Println(numbers) // [10 25 30 40 50] fmt.Println(subSlice) // [25 30 40]
為了避免任何意外的更改,您可以使用複製來建立切片的獨立版本:
// Using a literal numbers := []int{1, 2, 3, 4, 5} // Using the make function sliceOfStrings := make([]string, 5) // a slice of 5 strings, each
如果您需要一個大於其目前容量的切片,append 將在背景自動建立一個新的、更大的陣列並複製所有內容。這是非常有效率的,也是讓切片變得很棒的重要原因。當追加建立新陣列時,它會分配先前容量的兩倍 - 給您成長的空間!
這裡有一個 Go 的小秘密:雖然切片非常強大,但如果你不小心,它有時會導致記憶體洩漏。由於切片引用相同的底層數組,因此即使您只使用其中的一小部分,該數組也可能保留在記憶體中。
例如:
numbers := []int{1, 2, 3} fmt.Println(len(numbers)) // 3 fmt.Println(cap(numbers)) // 3 (same as length here)
在這種情況下,最好使用複製來建立一個真正獨立的切片,僅包含您需要的數據,從而釋放其餘記憶體。
numbers = append(numbers, 4) fmt.Println(len(numbers)) // 4 fmt.Println(cap(numbers)) // probably 6 now, depending on Go’s growth
需要多個維度?您也可以建立多維切片!這對於網格或表格之類的東西非常方便。只要聲明一個切片:
numbers := []int{1, 2, 3} numbers = append(numbers, 4, 5, 6) // Adding multiple elements at once fmt.Println(numbers) // [1 2 3 4 5 6]
每個「行」本身就是一個切片,因此您可以根據需要獨立生長它們。
numbers := []int{10, 20, 30, 40, 50} subSlice := numbers[1:4] // Just takes a "slice" of the original slice fmt.Println(subSlice) // [20 30 40]
nil 切片只是一個尚未初始化的切片。它的長度和容量為零,但仍然可以與諸如追加之類的函數一起使用而不會驚慌。
subSlice[0] = 25 fmt.Println(numbers) // [10 25 30 40 50] fmt.Println(subSlice) // [25 30 40]
當你追加到一個 nil 切片時,Go 會自動為你初始化它。這是一個巧妙的技巧,需要你袖手旁觀。
陷阱和最佳實踐?
注意共享記憶體:記住,切片與原始數組共享記憶體。這對於效能來說非常有用,但在對大型數組進行切片時要小心,以避免在記憶體中保留不需要的資料。
注意調整大小:當你追加時,如果目前容量已滿,Go 可能需要建立一個新的底層陣列。這比進行許多小的調整大小更有效,但如果您正在處理大型資料集,請注意開銷。
避免過早最佳化:Go 使用切片自動處理大量記憶體分配和調整大小。通常,嘗試對這些細節進行微觀管理最終可能會使您的程式碼變得更加混亂且效率降低。相信 Go 的切片機制在大多數情況下都能做正確的事。
以上是切片:Go 的骨幹!的詳細內容。更多資訊請關注PHP中文網其他相關文章!