數組是一組類型相同的,長度固定的,按數字編號排列的數據序列。因爲 go 語言中,數組的類型相同且長度固定,因此在聲明數組的時候,就會體現這兩個特色。數組
var array [5]int // [0 0 0 0 0]
複製代碼
數組經過 [SIZE](方括號內爲數組長度)
加上 TYPE(類型)
的形式聲明,上面的代碼就表示 array
變量爲一個長度爲 5
,且五個數據的類型都爲 int
。markdown
在以前介紹變量的時候,介紹過 int
類型的默認值爲 0
,因此 array
的值爲 [0 0 0 0 0]
。app
數組在初始化階段,須要經過 {}
的方式,指定數組每一個位置的具體值。函數
var array [3]int = [3]int{1, 2, 3} // [1 2 3]
複製代碼
能夠看到 {}
的前面也要帶上數組的長度與類型,因爲 go 可以進行類型推導,變量後聲明的類型顯得有點多餘,是能夠省略的。ui
var array = [3]int{1, 2, 3} // [1 2 3]
複製代碼
初始化的過程當中,咱們還能夠指定索引進行賦值,也就是沒必要給數組的每一個位置都安排上具體的值。spa
var array = [5]int{1: 77, 3: 77} // [0 77 0 77 0]
複製代碼
上面的數組輸出的結果爲:[0 77 0 77 0]
。和其餘語言同樣,數組的索引是從 0
開始的,咱們給索引爲 1
和 3
位置都指定了值爲 77
,其餘位置因爲沒有指定具體值,就是其類型的默認值。code
前面的案例都是指定了數組的長度,其實咱們能夠經過 [...]
的方式,告訴 go 編譯器,數組長度還沒有肯定,在初始化以後才能肯定其長度,而後 go 在編譯階段就會自動進行推導。orm
var array = [...]int{1, 2, 3, 4, 5} // [1 2 3 4 5]
fmt.Println("array length is", len(array))
複製代碼
咱們能夠經過 len
方法獲取數組的長度,上面代碼的運行結果以下:索引
若是咱們在指定索引的位置賦值了,最終長度取決於最末尾的索引,下面的代碼中,指定了索引 5
的值爲 77
,則數組的長度爲 6
。內存
var array = [...]int{1: 77, 5: 77} // [0 77 0 0 0 77]
fmt.Println("array length is", len(array))
複製代碼
與其餘語言同樣,數組的賦值和訪問都是經過 [Index]
操做的。
var array = [...]int{1, 2, 3}
array[0] = 100 // 索引 0 的位置從新賦值爲 100
fmt.Println("array is", array)
複製代碼
取值也是一樣的操做,咱們如今實現一個求數組平均數的函數:
func getAverage(array [5]int) float32 {
var sum int
var avg float32
for i := 0; i < 5; i++ {
sum += array[i]
}
avg = float32(sum) / 5
return avg
}
複製代碼
var array = [5]int{1, 2, 3, 4, 5}
fmt.Println("average is", getAverage(array))
複製代碼
多維數組的聲明,相對於一維數組,就是看前面有幾個 [SIZE]
。
var a1 [2][3]int // 二維數組
var a1 [2][3][4]int // 三維數組
複製代碼
咱們拿三維數組舉例,第一個 []
內的數字表示最外層數組的長度,日後以此類推。[2][3][4]int
表示最外層數組長度爲 2,第二層數組長度爲 3,最內層數組長度爲 4。其賦值方式也和一維數組同樣,只是多維數組須要將多個 {}
進行嵌套。
var a1 = [2][3][4]int{
{
{1, 2, 3, 4},
{1, 2, 3, 4},
{1, 2, 3, 4},
},
{
{1, 2, 3, 4},
{1, 2, 3, 4},
{1, 2, 3, 4},
},
}
fmt.Println(a1)
複製代碼
打印結果:
多維數組的訪問和一維數組同樣,也是經過 []
+ 數組索引,只是多維數組要訪問某個值須要多個 []
。
若是咱們要拿到下圖的 2
,訪問方式爲:array[0][1][1]
fmt.Println("array[0][1][1] = ", array[0][1][1])
複製代碼
前面介紹過,數組是一組類型相同且長度固定的數據集合,而切片就是一種比較抽象的數組,其長度不固定,聲明方式與數組相似([]
中不顯示註明數組長度,也不使用 [...]
的方式進行長度的推導):
var slice []int
複製代碼
切片的初始化與數組相似,只要省略掉 []
內註明的數組長度便可:
var s1 = []int{1, 2, 3}
s2 := []int{1, 2, 3} // 簡寫
複製代碼
除了這種字面量的聲明方式,還能夠經過 go 的內置方法:make
,來進行切片的初始化:
var s1 = make([]int, 3)
s2 := make([]int, 3) // 簡寫
複製代碼
make
方法的第二個參數表示切片的長度,雖然切片的長度可變,可是經過 make
方法建立切片時,須要指定一個長度。除了指定切片的長度,make
方法還支持傳入第三個參數,用來指定切片的『容量』,若是沒有指定切片的容量,那初始狀態切片的容量與長度一致。
func make([]T, len, cap)
複製代碼
長度指的是,切片內有多少個元素,而容量能夠理解爲,當前切片在內存中開闢了多大的空間。前面介紹過,能夠經過 len
方法獲取到數組的長度,獲取切片的長度也可使用該方法。要獲取切片的容量,可使用 cap
方法。
s1 := make([]int, 5)
fmt.Printf("The length of s1 is %d\n", len(s1))
fmt.Printf("The capacity of s1 is %d\n", cap(s1))
複製代碼
能夠看到初始狀態下,切片的長度與容量一致。若是要修改切片的長度,能夠經過 append
方法,在切片尾部追加一個新的值。
s1 := make([]int, 3, 5) // 聲明一個長度爲 3,容量爲 5 的切面
s1 = append(s1, 1) // 在尾部追加一個值,長度會變成 4
fmt.Printf("The length of s1 is %d\n", len(s1))
fmt.Printf("The capacity of s1 is %d\n", cap(s1))
複製代碼
append
方法是能夠接受多個參數,咱們在追加一個值以後,繼續調用 append
方法,往切片後再追加兩個值:
s1 := make([]int, 3, 5)
s1 = append(s1, 1)
s1 = append(s1, 2, 3)
fmt.Println(s1) // [0 0 0 1 2 3]
fmt.Printf("The length of s1 is %d\n", len(s1))
fmt.Printf("The capacity of s1 is %d\n", cap(s1))
複製代碼
此時的切片的長度已經變成了 6,超過了切片的容量,那這個時候切換的容量會不會也變成 6?
根據輸出的結果,此時切片的容量變成了 10,這意味着切片的容量的擴充是在以前的基礎上進行翻倍操做的。爲了驗證這個結論,咱們在切片後繼續追加 5 個值,讓切片的長度變成 11,超出當前的容量,看看容量會變成多少。
s1 := make([]int, 3, 5)
s1 = append(s1, 1)
s1 = append(s1, 2, 3)
s1 = append(s1, 4, 5, 6, 7, 8)
fmt.Printf("The length of s1 is %d\n", len(s1))
fmt.Printf("The capacity of s1 is %d\n", cap(s1))
複製代碼
能夠看到切片的容量變成了 20,這也驗證了咱們以前的結論,當切片長度超過了其容量,容量會在原來的基礎上翻倍。那若是切片容量達到了 2000,長度超過 2000,容量也會變成 4000 嗎?
s1 := make([]int, 1024)
s1 = append(s1, 1)
fmt.Printf("\nThe length of s1 is %d\n", len(s1))
fmt.Printf("The capacity of s1 is %d\n", cap(s1))
複製代碼
能夠看到,咱們新定義的切片長度爲 1024,在長度變成 1025 的時候,容量並無翻倍。爲了不切片容量無休止的擴展,go 規定若是當前切片的長度大於 1024 ,在長度超過其容量時,只會增長 25% 的容量。
切片之因此叫切片,是由於它能夠經過切出數組中的某一塊來建立。語法規則也很簡單:Array[start:end]
。
arr := [5]int{1, 2, 3, 4, 5}
slice := arr[1:3]
fmt.Println(slice) // [2 3]
複製代碼
arr[1:3]
表示將數組的從索引爲 1 的位置一直到索引爲 3 的位置(不包括 3)截取出來,造成一個切片。固然這個開頭結尾的數字也是能夠省略的,若是咱們若是咱們省略開頭就表示截取開始的位置爲 0,省略結尾就表示截取結束的位置一直到數組的最後一位。
arr := [5]int{1, 2, 3, 4, 5}
slice := arr[1:]
fmt.Println(slice) // [2 3 4 5]
複製代碼
經過省略截取的開頭和結尾,咱們就能將一個數組進行一次拷貝操做,而後造成一個切片。(PS. 截取操做造成的新數據是一個切片)
arr := [5]int{1, 2, 3, 4, 5}
slice := arr[:]
fmt.Printf("slice = %v, slice type is %T", slice, slice)
複製代碼