多维数组的索引与切片_「GCTT 出品」Go 系列教程——11. 数组和切片
Go語言中文網,致力于每日分享編碼知識,歡迎關注我,會有意想不到的收獲!
Go 系列教程是非常棒的一套初學者教程,入門就它了。
「GCTT 出品」Go 系列教程——1. 介紹與安裝
「GCTT 出品」Go 系列教程——2. Hello World
「GCTT 出品」Go 系列教程——3. 變量
「GCTT 出品」Go 系列教程——4. 類型
「GCTT 出品」Go 系列教程——5. 常量
「GCTT 出品」Go 系列教程——6. 函數(Function)
「GCTT 出品」Go 系列教程——7. 包
Go 系列教程——8. if-else 語句
「GCTT 出品」Go 系列教程——9. 循環
「GCTT 出品」Go 系列教程——10. switch 語句
這是 Golang 系列教程中的第 11 篇。在本章教程中,我們將討論 Go 語言中的數組和切片。
01 數組
數組是同一類型元素的集合。例如,整數集合 5,8,9,79,76 形成一個數組。Go 語言中不允許混合不同類型的元素,例如包含字符串和整數的數組。(譯者注:當然,如果是 interface{} 類型數組,可以包含任意類型)
數組的聲明
一個數組的表示形式為 [n]T。n 表示數組中元素的數量,T 代表每個元素的類型。元素的數量 n 也是該類型的一部分(稍后我們將詳細討論這一點)。
可以使用不同的方式來聲明數組,讓我們一個一個的來看。
var a[3]int 聲明了一個長度為 3 的整型數組。數組中的所有元素都被自動賦值為數組類型的零值。 在這種情況下,a 是一個整型數組,因此 a 的所有元素都被賦值為 0,即 int 型的零值。運行上述程序將 輸出 [0 0 0]。
數組的索引從 0 開始到 length - 1 結束。讓我們給上面的數組賦值。
a[0] 將值賦給數組的第一個元素。該程序將 輸出 [12 78 50]。
讓我們使用 簡略聲明 來創建相同的數組。
上面的程序將會打印相同的 輸出 [12 78 50]。
在簡略聲明中,不需要將數組中所有的元素賦值。
在上述程序中的第 8 行 a := [3]int{12} 聲明一個長度為 3 的數組,但只提供了一個值 12,剩下的 2 個元素自動賦值為 0。這個程序將輸出 [12 0 0]。
你甚至可以忽略聲明數組的長度,并用 ... 代替,讓編譯器為你自動計算長度,這在下面的程序中實現。
數組的大小是類型的一部分。因此 [5]int 和 [25]int 是不同類型。數組不能調整大小,不要擔心這個限制,因為 slices 的存在能解決這個問題。
在上述程序的第 6 行中, 我們試圖將類型 [3]int 的變量賦給類型為 [5]int 的變量,這是不允許的,因此編譯器將拋出錯誤 main.go:6: cannot use a (type [3]int) as type [5]int in assignment。
數組是值類型
Go 中的數組是值類型而不是引用類型。這意味著當數組賦值給一個新的變量時,該變量會得到一個原始數組的一個副本。如果對新變量進行更改,則不會影響原始數組。
在上述程序的第 7 行,a 的副本被賦給 b。在第 8 行中,b 的第一個元素改為 Singapore。這不會在原始數組 a 中反映出來。該程序將 輸出,
a is [USA China India Germany France] b is [Singapore China India Germany France]同樣,當數組作為參數傳遞給函數時,它們是按值傳遞,而原始數組保持不變。
在上述程序的 13 行中, 數組 num 實際上是通過值傳遞給函數 changeLocal,數組不會因為函數調用而改變。這個程序將輸出,
before passing to function [5 6 7 8 8]inside function [55 6 7 8 8]after passing to function [5 6 7 8 8]數組的長度
通過將數組作為參數傳遞給 len 函數,可以得到數組的長度。
上面的程序輸出為 length of a is 4。
使用 range 迭代數組
for 循環可用于遍歷數組中的元素。
上面的程序使用 for 循環遍歷數組中的元素,從索引 0 到 length of the array - 1。這個程序運行后打印出,
0 th element of a is 67.70 1 th element of a is 89.80 2 th element of a is 21.00 3 th element of a is 78.00Go 提供了一種更好、更簡潔的方法,通過使用 for 循環的 range 方法來遍歷數組。range 返回索引和該索引處的值。讓我們使用 range 重寫上面的代碼。我們還可以獲取數組中所有元素的總和。
上述程序的第 8 行 for i, v := range a 利用的是 for 循環 range 方式。 它將返回索引和該索引處的值。 我們打印這些值,并計算數組 a 中所有元素的總和。 程序的 輸出是,
0 the element of a is 67.701 the element of a is 89.802 the element of a is 21.003 the element of a is 78.00sum of all elements of a 256.5如果你只需要值并希望忽略索引,則可以通過用 _ 空白標識符替換索引來執行。
for _, v := range a { // ignores index }上面的 for 循環忽略索引,同樣值也可以被忽略。
多維數組
到目前為止我們創建的數組都是一維的,Go 語言可以創建多維數組。
在上述程序的第 17 行,用簡略語法聲明一個二維字符串數組 a 。20 行末尾的逗號是必需的。這是因為根據 Go 語言的規則自動插入分號。至于為什么這是必要的,如果你想了解更多,請閱讀 https://golang.org/doc/effective_go.html#semicolons。
另外一個二維數組 b 在 23 行聲明,字符串通過每個索引一個一個添加。這是另一種初始化二維數組的方法。
第 7 行的 printarray 函數使用兩個 range 循環來打印二維數組的內容。上述程序的 輸出是
lion tigercat dogpigeon peacockapple samsungmicrosoft googleAT&T T-Mobile這就是數組,盡管數組看上去似乎足夠靈活,但是它們具有固定長度的限制,不可能增加數組的長度。這就要用到 切片 了。事實上,在 Go 中,切片比傳統數組更常見。
02 切片
切片是由數組建立的一種方便、靈活且功能強大的包裝(Wrapper)。切片本身不擁有任何數據。它們只是對現有數組的引用。
創建一個切片
帶有 T 類型元素的切片由 []T 表示
使用語法 a[start:end] 創建一個從 a 數組索引 start 開始到 end - 1 結束的切片。因此,在上述程序的第 9 行中, a[1:4] 從索引 1 到 3 創建了 a 數組的一個切片表示。因此, 切片 b 的值為 [77 78 79]。
讓我們看看另一種創建切片的方法。
在上述程序的第 9 行,c:= [] int {6,7,8} 創建一個有 3 個整型元素的數組,并返回一個存儲在 c 中的切片引用。
切片的修改
切片自己不擁有任何數據。它只是底層數組的一種表示。對切片所做的任何修改都會反映在底層數組中。
在上述程序的第 9 行,我們根據數組索引 2,3,4 創建一個切片 dslice。for 循環將這些索引中的值逐個遞增。當我們使用 for 循環打印數組時,我們可以看到對切片的更改反映在數組中。該程序的輸出是
array before [57 89 90 82 100 78 67 69 59] array after [57 89 91 83 101 78 67 69 59]當多個切片共用相同的底層數組時,每個切片所做的更改將反映在數組中。
在 9 行中,numa [:] 缺少開始和結束值。開始和結束的默認值分別為 0 和 len (numa)。兩個切片 nums1 和 nums2 共享相同的數組。該程序的輸出是
array before change 1 [78 79 80] array after modification to slice nums1 [100 79 80] array after modification to slice nums2 [100 101 80]從輸出中可以清楚地看出,當切片共享同一個數組時,每個所做的修改都會反映在數組中。
切片的長度和容量
切片的長度是切片中的元素數。切片的容量是從創建切片索引開始的底層數組中元素數。
讓我們寫一段代碼來更好地理解這點。
在上面的程序中,fruitslice 是從 fruitarray 的索引 1 和 2 創建的。 因此,fruitlice 的長度為 2。
fruitarray 的長度是 7。fruiteslice 是從 fruitarray 的索引 1 創建的。因此, fruitslice 的容量是從 fruitarray 索引為 1 開始,也就是說從 orange 開始,該值是 6。因此, fruitslice 的容量為 6。該程序輸出切片的 長度為 2 容量為 6 。
切片可以重置其容量。任何超出這一點將導致程序運行時拋出錯誤。
在上述程序的第 11 行中,fruitslice 的容量是重置的。以上程序輸出為,
length of slice 2 capacity 6 After re-slicing length is 6 and capacity is 6使用 make 創建一個切片
func make([]T,len,cap)[]T 通過傳遞類型,長度和容量來創建切片。容量是可選參數, 默認值為切片長度。make 函數創建一個數組,并返回引用該數組的切片。
使用 make 創建切片時默認情況下這些值為零。上述程序的輸出為 [0 0 0 0 0]。
追加切片元素
正如我們已經知道數組的長度是固定的,它的長度不能增加。 切片是動態的,使用 append 可以將新元素追加到切片上。append 函數的定義是 func append(s[]T,x ... T)[]T。
x ... T 在函數定義中表示該函數接受參數 x 的個數是可變的。這些類型的函數被稱為可變函數。
有一個問題可能會困擾你。如果切片由數組支持,并且數組本身的長度是固定的,那么切片如何具有動態長度。以及內部發生了什么,當新的元素被添加到切片時,會創建一個新的數組。現有數組的元素被復制到這個新數組中,并返回這個新數組的新切片引用。現在新切片的容量是舊切片的兩倍。很酷吧 。下面的程序會讓你清晰理解。
在上述程序中,cars 的容量最初是 3。在第 10 行,我們給 cars 添加了一個新的元素,并把 append(cars, "Toyota") 返回的切片賦值給 cars。現在 cars 的容量翻了一番,變成了 6。上述程序的輸出是
cars: [Ferrari Honda Ford] has old length 3 and capacity 3 cars: [Ferrari Honda Ford Toyota] has new length 4 and capacity 6切片類型的零值為 nil。一個 nil 切片的長度和容量為 0。可以使用 append 函數將值追加到 nil 切片。
在上面的程序 names 是 nil,我們已經添加 3 個字符串給 names。該程序的輸出是
slice is nil going to append names contents: [John Sebastian Vinay]也可以使用 ... 運算符將一個切片添加到另一個切片。 你可以在可變參數函數教程中了解有關此運算符的更多信息。
在上述程序的第 10 行,food 是通過 append(veggies, fruits...) 創建。程序的輸出為 food: [potatoes tomatoes brinjal oranges apples]。
切片的函數傳遞
我們可以認為,切片在內部可由一個結構體類型表示。這是它的表現形式,
切片包含長度、容量和指向數組第零個元素的指針。當切片傳遞給函數時,即使它通過值傳遞,指針變量也將引用相同的底層數組。因此,當切片作為參數傳遞給函數時,函數內所做的更改也會在函數外可見。讓我們寫一個程序來檢查這點。
上述程序的行號 17 中,調用函數將切片中的每個元素遞減 2。在函數調用后打印切片時,這些更改是可見的。如果你還記得,這是不同于數組的,對于函數中一個數組的變化在函數外是不可見的。上述程序的輸出是,
array before function call [8 7 6] array after function call [6 5 4]多維切片
類似于數組,切片可以有多個維度。
程序的輸出為,
C C++ JavaScript Go Rust03 內存優化
切片持有對底層數組的引用。只要切片在內存中,數組就不能被垃圾回收。在內存管理方面,這是需要注意的。讓我們假設我們有一個非常大的數組,我們只想處理它的一小部分。然后,我們由這個數組創建一個切片,并開始處理切片。這里需要重點注意的是,在切片引用時數組仍然存在內存中。
一種解決方法是使用 copy 函數 func copy(dst,src[]T)int 來生成一個切片的副本。這樣我們可以使用新的切片,原始數組可以被垃圾回收。
在上述程序的第 9 行,neededCountries := countries[:len(countries)-2 創建一個去掉尾部 2 個元素的切片 countries,在上述程序的 11 行,將 neededCountries 復制到 countriesCpy 同時在函數的下一行返回 countriesCpy。現在 countries 數組可以被垃圾回收, 因為 neededCountries 不再被引用。
我已經把我們迄今為止所討論的所有概念整理成一個程序。 你可以從 github https://github.com/golangbot/arraysandslices 下載它。
這是數組和切片。謝謝你的閱讀。請您留下寶貴的意見和意見。
上一教程 - 「GCTT 出品」Go 系列教程——10. switch 語句
下一教程 - 可變函數
總結
以上是生活随笔為你收集整理的多维数组的索引与切片_「GCTT 出品」Go 系列教程——11. 数组和切片的全部內容,希望文章能夠幫你解決所遇到的問題。

- 上一篇: 抖音右上角一个小黄点是什么_抖音用户更喜
- 下一篇: 比亚迪秦wince玩游戏_【新闻】1.5