網頁

2021/6/19

Golang Slice 簡單範例

Go語言的Slice(切片)是用來描述array(陣列)區段的參照,本身不儲存值,長度可變。


Slice的用途類似Java的ArrayList,其背後都是陣列,大小可動態增加,裝載連續多個同型態的元素。


Slice用來表示array的一個區段,語法為array變數後加上[low:high]取得,lowhigh代表截取陣列的始末index位置,含起始元素但不含結束元素。如果起始index為第一個位置或結束index為最後一個位置的下一個位置可省略。起始index相同則截取0個元素。

a := [5]string{"a", "b", "c", "d", "e"} // 宣告陣列變數a及賦予元素值 

s := a[1:3]
fmt.Println(s) // [b c]

s = a[:3] // 相當於a[0:3]
fmt.Println(s) // [a b c]

s = a[3:] // 相當於a[3:5]
fmt.Println(s) // [d e]

s = a[1:1] // 截取0個元素
fmt.Println(s) // []

截取index的值不可為負,不可超過元素長度,起始index要小於結束index,否則編譯錯誤。

a := [5]string{"a", "b", "c", "d", "e"} // index from 0-4

s := a[-1:] // invalid slice index -1 (index must be non-negative)

s = a[:6] // invalid slice index 6 (out of bounds for 5-element array)

s = a[3:1] // invalid slice index: 3 > 1

除了從array截取,也可用slice literal語法宣告slice及賦值,語法類似arrays literal但不在方括弧設定長度。

s := []string{"a", "b", "c", "d", "e"} // slice literal
fmt.Println(s) // [a b c d e]

相當於宣告陣列在截取整段array為slice。

a := [5]string{"a", "b", "c", "d", "e"}
s := a[:] // 截取開頭到最後位置的slice
fmt.Println(s) // [a b c d e]

Slice僅是array的參照而不儲存值,因此當兩個slice參照同個array的元素被異動時都會被影響。

a := [5]string{"a", "b", "c", "d", "e"}

s1 := a[:3] // [a b c]
s2 := a[2:] // [c d e]

a[2] = "X"
fmt.Println(s1) // [a b X]
fmt.Println(s2) // [X d e]

Slice除了長度(length)外有容量(capacity)。
length代表slice所包含的元素數量,使用內建函數len(ss)取得;
capacity代表從slice第一個參照index位置起算的array長度,使用內建函數cap(s)取得。

a := [5]string{"a", "b", "c", "d"} // 第五個元素為空字串""
fmt.Println(len(a)) // 5

s := a[1:3] // [b c]
fmt.Println(len(s)) // 2, slice所含元素的個數
fmt.Println(cap(s)) // 4, 從slice的第一個參照'b'位置起算到array最後位置的長度

一個slice的來源若為另一個slice,參照的仍是同個array。

a := [5]string{"a", "b", "c", "d", "e"}

s1 := a[:3] // [a b c]
fmt.Println(cap(s1)) // 5

s2 := s1[2:]
fmt.Println(s2) // [c]
fmt.Println(cap(s2)) // 3, count from index of "c" to final index of array a 

宣告空slice的語法為[]T,後接的T代表元素型態。例如下面宣告一個型態為int的空slice變數s。length及capacity皆為0代表沒有參照任何array,所以為nil

var s []int
fmt.Println(s) // []
fmt.Println(len(s)) // 0
fmt.Println(cap(s)) // 0
fmt.Println(s == nil) // true

若slice的length為0但capacity不為0則不為nil

a := [5]string{"a", "b", "c", "d", "e"}

s := a[0:0]
fmt.Println(len(s)) // 0
fmt.Println(cap(s)) // 5
fmt.Println(s == nil) // false

若要建立一個指定長度的空slice,使用內建函式make([]T, length, capacity),第一個參數[]T為slice資料型態,第二個參數length為slice長度,第三個參數capacitiy為參考的陣列的長度。

s = make([]int, 5)
fmt.Println(s) // [0 0 0 0 0]
fmt.Println(len(s)) // 5
fmt.Println(cap(s)) // 5

上面以make()建立的slice相當於以下先建立array在截取slice。

s := new([5]int)[:] // create an array with length 5 then get slice
fmt.Println(s) // [0 0 0 0 0]
fmt.Println(len(s)) // 5
fmt.Println(cap(s)) // 5

加入新元素到slice可使用內建函式append(s S, x ...T) S加入新的元素。如果原參照的array空間不足則會將內容複製到到另一個更大空間的array並重新參照。

s := make([]int, 3)
fmt.Println(s) // [0 0 0]
fmt.Println(len(s)) // 3
fmt.Println(cap(s)) // 3

s = append(s, 1) // add new element
fmt.Println(s) // [0 0 0 1]
fmt.Println(len(s)) // 4
fmt.Println(cap(s)) // 6, reallocated array length

複製slice到另個可使用內建函式copy(dst, src []T) int,參數dst為複製目標slice,src為複製來源slice,複製目標及來源的型態必須相同。返回值代表複製的元素個數。

src := []int{1, 2, 3, 4, 5}
dst := make([]int, 3)
fmt.Println(dst) // [0 0 0]

n := copy(dst, src)
fmt.Println(dst) // [1 2 3]
fmt.Println(n) // 3, the numbers of elemnets copied


使用range走訪slice如下,回傳的第一個值i為元素的index,第二個值v為元素的值。

s := []string{"a", "b", "c", "d", "e"}

for i, v := range s {
   fmt.Printf("index=%d, value=%s\n", i, v)
}

執行印出如下:

index=0, value=a
index=1, value=b
index=2, value=c
index=3, value=d
index=4, value=e


沒有留言:

張貼留言