在GO當中,有兩種資料結構是能夠儲存多項相同型態資料的,分別為Array
和Slice
。
[]int
就是int slice,指的是slice裡頭的元素皆為int。無論是Array或是Slice,皆必須指定裡頭資料的型別,且裡頭資料的型別必須一致。
陣列的長度在宣告後無法改變,若在某些index未賦予值,則該index值為此type的預設值,像是int
的預設值就是0
package main
import "fmt"
func main() {
var a [5]int
a[0] = 10
a[1] = 100
a[2] = 1000
fmt.Println(a)
}
運算可得結果
[10 100 1000 0 0]
此外
零值
Array
可以只選用其中的某段資料[...]
來讓系統設定array長度package main
import "fmt"
func main() {
b := [5]int{1, 10, 100}
fmt.Println(b)
c := [5]int{2, 20, 200, 2000}
fmt.Println(c[1:3])
d := [...]int{3, 30, 300, 3000}
fmt.Println(d)
}
運算後可得結果
[1 10 100 0 0]
[20 200]
[3 30 300 3000]
4
e:= []int{1,2}
在[]
當中沒有任何東西的宣告是屬於Slice
,而不是省略長度的Array
,Array
一定需要賦予長度!
An array has a fixed size.
A slice, on the other hand, is a dynamically-sized,
flexible view into the elements of an array.
Slice可以視為長度不固定的Array。
宣告時中括號[]裡為空
把Slice
拆開來看,這玩意包含了三樣東西:
len
,指的是現在的長度cap
,指的是最大能容納的長度ptr
,透過指針,我們能與別人共用同個地方以下為幾種宣告Slice
的方式
package main
import (
"fmt"
)
func main() {
a := make([]int, 2)
fmt.Println(a, len(a), cap(a), len(a) == 0, a == nil)
b := make([]int, 2, 4)
fmt.Println(b, len(b), cap(b), len(b) == 0, b == nil)
var c = []int{}
fmt.Println(c, len(c), cap(c), len(c) == 0, c == nil)
var d []int
fmt.Println(d, len(d), cap(d), len(d) == 0, d == nil)
e := []string{"ironman", "2021"}
fmt.Println(e, len(e), cap(e), len(e) == 0, e == nil)
}
運算後得到結果
[0 0] 2 2 false false
[0 0] 2 4 false false
[] 0 0 true false
[] 0 0 true true
[ironman 2021] 2 2 false false
nil
Slice並不是真正存值,而是透過指針指到更下面的地方,記憶體中的某個陣列
這也是為什麼說可以跟別人共用的原因。
如果SliceA跟SliceB都是一樣的值,底層陣列只要儲存一份資料,這樣也能節省記憶體空間。
package main
import "fmt"
func main() {
a := make([]int, 0, 10)
b := append(a, 1, 2, 3)
_ = append(a, 99, 88, 77)
fmt.Println(b)
aa := make([]int, 0, 2)
bb := append(aa, 1, 2, 3)
_ = append(aa, 99, 88, 77)
fmt.Println(bb)
}
運行後可得
[99 88 77]
[1 2 3]
在足夠容量
中沒發生災情,但是在超小容量
中卻因為後來的_
做了append
,
導致我的aa
中的值也被改了?
沒錯,這就是可以看到pointer
的地方,原因在於底層的陣列被後來的_
蓋掉了。
這一次所介紹的Array
與Slice
就類型與用途來說就完全與Python的List
或是Tuple
完全不同了,這邊就會需要讀者適應一下,無論是固定類型長度,或者是使用規則方面,但這樣的學習與使用方式,也會讓我們更暸解這兩種資料結構的底層運作邏輯。