Slice 變數: 進階陣列

Golang 基礎: Slice 變數: 進階陣列

Array 與 Slice 使用情境比較

  • Array:清單的長度是固定的(fixed length),屬於原生型別(primitive type),較少在程式中使用。
  • Slice:可以增加或減少清單的長度,使用 [] 定義,例如,[]byte 是 byte slice,指元素為 byte 的 slice;[]string 是 string slice,指元素為 string 的 slice。

Slice 的 Pointer & capacity 及 length

項目 說明
Pointer (ptr) 這個 pointer 會指向實際上在底層的 array。
Capacity (cap) 從 slice 的第一個元素開始算起,它底層 array 的元素數目,cap 的數量再擴展時會是 1, 2, 4, 8, 16
Length (len) 該 slice 中的元素數目

使用 Slice 變數時,會先指向該 Slice,然後 Pointer (ptr) 會指向這個 Slice 對應的 Array

建立 slice 變數

透過 make 可以建立「空 slice」

適合用會對 slice 中特定位置元素進行操作時

make(類型, 長度, capacity)

employee_list := make([]string, 3)
fmt.Println("empty employee_list:", employee_list)

employee_list[0] = "KJ"
employee_list[1] = "Kay"
employee_list[2] = "Jay"
fmt.Println("all employee:", employee_list)
fmt.Println("3rd employee:", employee_list[2])
// empty employee_list: [  ]
// all employee: [KJ Kay Jay]
// 3rd employee: Jay

建立一個帶有資料的 string slice

適合用在知道 slice 裡面的元素有哪些時

employee_list := []string{"KJ", "Kay", "Jay"}
fmt.Println("all employee:", employee_list)
// all employee: [KJ Kay Jay]

空的 slice

一般會搭配 append 使用

var employee_list []string

employee_list = append(employee_list, "KJ")
employee_list = append(employee_list, "Kay")
employee_list = append(employee_list, "Jay")
fmt.Println("all employee:", employee_list)
fmt.Println("3rd employee:", employee_list[2])
// all employee: [KJ Kay Jay]
// 3rd employee: Jay

其他類型 Slice

// integer slice
integer_slice := []int{2, 3, 5, 7, 11, 13}
fmt.Println(integer_slice)
// [2 3 5 7 11 13]



// boolean slice
boolean_slice := []bool{true, false, true, true, false, true}
// [true false true true false true]
fmt.Println(boolean_slice)


// struct slice
struct_slice := []struct {
	number   int
	is_exist bool
}{
	{2, true},
	{3, false},
	{5, true},
	{7, true},
	{11, false},
	{13, true},
}
// [{2 true} {3 false} {5 true} {7 true} {11 false} {13 true}]
fmt.Println(struct_slice)

多維度 Slice

multi_dimension_slice := make([][]int, 3)
// [[] [] []]
fmt.Println(multi_dimension_slice)

// 賦值
multi_dimension_slice[0] = []int{1}
multi_dimension_slice[1] = []int{2}
multi_dimension_slice[2] = []int{3}
// [[1] [2] [3]]
fmt.Println(multi_dimension_slice)
multi_dimension_slice := [][]int{
	[]int{1},
	[]int{2},
	[]int{3},
}
// [[1] [2] [3]]
fmt.Println(multi_dimension_slice)

Slice 與 Array 建立差異

// 沒有使用 ...,建立出來的會是 slice
sliceList := []string{"North", "East", "South", "West"}
// slice 4
fmt.Println(reflect.TypeOf(sliceList).Kind(), len(sliceList))

// 使用 ...,建立出來的會是 array
arrayList := [...]string{"North", "East", "South", "West"}
// array 4
fmt.Println(reflect.TypeOf(arrayList).Kind(), len(arrayList))

slice 資料數量

employee_list := make([]string, 3)

employee_list[0] = "KJ"
employee_list[1] = "Kay"
employee_list[2] = "Jay"
fmt.Println("len:", len(employee_list))
// len: 3

加入 slice 資料

加入單一資料到 slice

employee_list := make([]string, 3)

employee_list[0] = "KJ"
employee_list[1] = "Kay"
employee_list[2] = "Jay"

employee_list = append(employee_list, "Musk")
employee_list = append(employee_list, "Bill", "Jim")
fmt.Println("all employee after append:", employee_list)
// all employee after append: [KJ Kay Jay Musk Bill Jim]

加入另一 slice 變數資料

employee_list_slice := []string{"KJ", "Kay"}
other_employee_slice := []string{"Jay", "Jeff"}

// 等同於 append(employee_list_slice, other_employee_slice[0], other_employee_slice[1], other_employee_slice[2])
employee_list_slice = append(employee_list_slice, other_employee_slice...)
// [KJ Kay Jay Jeff]
fmt.Println(employee_list_slice)                                          

複製 slice 變數

複製的 slice 變數是傳值的方式,所以複製變數的異動不會影響先前的 slice 變數

copy(目標變數, 來源變數) int

copy() 回傳的值是複製了多少元素

employee_list := make([]string, 3)

employee_list[0] = "KJ"
employee_list[1] = "Kay"
employee_list[2] = "Jay"

// 複製 slice 變數
copy_employee_list := make([]string, len(employee_list))
copy(copy_employee_list, employee_list)
fmt.Println("all employee:", employee_list)
fmt.Println("all copy employee:", copy_employee_list)
// all employee: [KJ Kay Jay]
// all copy employee: [KJ Kay Jay]


// 變更複製的 slice
copy_employee_list[2] = "Change Name"
fmt.Println("all employee after change:", employee_list)
fmt.Println("all copy employee after change:", copy_employee_list)
// all employee after change: [KJ Kay Jay]
// all copy employee after change: [KJ Kay Change Name]

複製元素大小影響

  • cloneScores 的元素數量如果「多於」被複製進去的元素時,會用 zero value 去補
  • cloneScores 的元素數量如果「少於」被複製進去的元素時,超過的元素不會被複製進去
scores := []int{1, 2, 3, 4, 5}

// STEP 1:建立空 slice
cloneScoresMore := make([]int, 7)
cloneScoresLess := make([]int, 3)

// STEP 2:使用 copy 複製 scores 元素
copy(cloneScoresMore, scores)
copy(cloneScoresLess, scores)

// cloneScores 的元素數量如果「多於」被複製進去的元素時,會用 zero value 去補
// [1 2 3 4 5 0 0]
fmt.Println(cloneScoresMore)
// cloneScores 的元素數量如果「少於」被複製進去的元素時,超過的元素不會被複製進去
// [1 2 3]
fmt.Println(cloneScoresLess)

取得指定 slice 範圍的變數

employee_list := make([]string, 6)

employee_list[0] = "KJ"
employee_list[1] = "Kay"
employee_list[2] = "Jay"
employee_list[3] = "Musk"
employee_list[4] = "Bill"
employee_list[5] = "Jim"

slice[<從第幾個元素>:<到第幾個元素(不含此元素)>]

slice_employee_list := employee_list[2:5]
fmt.Println("employee_list:", employee_list)
fmt.Println("slice_employee_list:", slice_employee_list)
// employee_list: [KJ Kay Jay Musk Bill Jim]
// slice_employee_list: [Jay Musk Bill]

slice[:<到第幾個元素(不含此元素)>]

slice_employee_list := employee_list[:3]
fmt.Println("employee_list:", employee_list)
fmt.Println("slice_employee_list:", slice_employee_list)
// employee_list: [KJ Kay Jay Musk Bill Jim]
// slice_employee_list: [KJ Kay Jay]

slice[<從第幾個元素>:]

slice_employee_list := employee_list[2:]
fmt.Println("employee_list:", employee_list)
fmt.Println("slice_employee_list:", slice_employee_list)
// employee_list: [KJ Kay Jay Musk Bill Jim]
// slice_employee_list: [Jay Musk Bill Jim]

移除元素

移除最後一個元素

scores := []int{1, 2, 3, 4, 5}
removeLastIndex := scores[:len(scores)-1]
// [1,2,3,4]
fmt.Println(removeLastIndex)

參考資料