Go的100天之旅-06陣列和Slice

後廠村海盜發表於2020-07-16

陣列

Go的陣列和其它語言基本上一樣,是長度固定的特定型別元素組成的序列,這基本上是所有語言陣列的特性。和其它語言相比差異主要在宣告和初始化的寫法上,下面是簡單宣告一個陣列:

var a [5]int 
fmt.Println(a[0]) 
fmt.Println(fmt.Println(a[len(a)-1])) 

上面的a是一個長度為5的整數陣列,如果沒有給定初始值它裡面的元素預設值是0Go陣列的下標是從0開始的,len函式返回陣列中元素的個數。我們可以在宣告陣列的時候初始化它的值:

var m [3]int = [3]int{1, 2, 3}
var n [3]int = [3]int{2, 3}

這裡的mn都是長度為3的陣列,m對應的值是1, 2, 3而由於n初始化的時候只有2個值,因此它裡面的值是2, 3, 0
如果採用簡單宣告:=的方式宣告一個陣列,可以指定陣列的大小,也可以不指定大小這時它會根據初始化值的個數來確定:

a := [10]int{} //元素都為0
b := [...]int{1, 2} //長度為2

Go 也可以直接指定一個索引和值,來初始化,如果宣告的時候長度不指定,那最大的索引加1就是陣列的長度:

a := [10]int{1:2} // 長度10,a[1] = 2 其它為0
b := [...]int{1:2, 10:1} //長度11,a[1] = 2 a[10] = 1其它為0

陣列a長度宣告是10,只給了索引1的值為2,其餘都為0。陣列b宣告的時候索引12101,它的長度是11

修改陣列中某個索引的值方式和其它語言一樣:

a := [10]int{}
a[0] = 10

陣列的型別是由元素的型別和長度共同決定的,[3]int[4]int是兩種不同的陣列型別。因此:

a := [3]int{1, 2, 3}
a = [4]int{1, 2, 3, 4}

編譯的時候會報錯,而:

a := [3]int{1, 2, 3}
a = [3]int{4, 5, 6}

是正確的

Slice

上面說的陣列長度是固定,使用的時候不是很靈活,slice的長度是可變,簡單宣告一個未初始化的slice

var a []int
print(len(a))
print(cap(a))

slice也可以利用len返回它的長度,剛才宣告的slice長度為0。除了長度slice還有一個容量cap的概念,用cap可以返回它的容量。長度不能超過它的容量。slice的宣告也可以用make,用make宣告可以指定容量和可以不指定容量,這時容量和長度一致:

a := make([]int, 10) //長度為10,容量為10
a := make([]int, 10, 12) //長度為10 容量為12

slice可以進行切片操作slice[i:j],建立一個新的slice,新的slice範圍是原來slice下標ij-1,也可以不指定下標slice[:j]則是預設從0j-1,同理如果slice[i:]就是從i到最後一個元素,下面是一個簡單的例子:

a := []int {1, 2, 3, 4, 5}
b = a[1:2]
c = a[:2]
d = a[1:]

需要注意的是切片操作slice[i:j]j可以大於slice的長度,只要它小於容量

剛才一直講到容量,那它到底有什麼實際意義呢?開始slice的時候說過它長度是可變的,哪怎麼改變了?通過append就可以對slice追加元素,這時容量就有作用了,如果append的時候當前長度小於容量,那slice不會擴大容量,也不會申請新的空間,而是在原來的基礎上把長度加1就行了,如果容量等於長度,則會擴容,擴容會申請新的空間。

package main

func main() {
	a := make([]int, 10, 11)
	a = append(a, 1)
	println(len(a), cap(a)) // 11 11

	a = append(a, 1)
	println(len(a), cap(a)) // 12 12
}

相關文章