Slice Type


  • Slice 跟陣列使用起來很像,最大的不同是,陣列是值, Slice 是參考到一個陣列。

建立

  • 要建立一個全新的 Slice有兩種方法,一個是使用 make函式:
1
2
3
4
5
6
7
8
9
package main

import "fmt"

func main() {
slice := make([]int, 5)

fmt.Println(slice) // [0 0 0 0 0]
}
  • 另一個方法是指定初值,雖然用法跟陣列很像,但形態不一樣就不能拿來一起比較。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
package main

import "fmt"
import "reflect"

func main() {
slice := []int{1, 2, 3, 4, 5}

fmt.Println(slice) // [1 2 3 4 5]

arr := [...]int{1, 2, 3, 4, 5}

fmt.Println(reflect.TypeOf(slice)) // []int
fmt.Println(reflect.TypeOf(arr)) // [5]int
fmt.Println(arr == slice) // invalid operation: arr == slice (mismatched types [5]int and []int)
}
  • Slice 是參考到一個陣列
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
package main

import "fmt"

func main() {
slice := []int{1, 2, 3, 4, 5}
ref := slice

fmt.Println(slice) // [1 2 3 4 5]
fmt.Println(ref) // [1 2 3 4 5]

slice[0] = 100

fmt.Println(slice) // [100 2 3 4 5]
fmt.Println(ref) // [100 2 3 4 5]

ref[4] = 500

fmt.Println(slice) // [100 2 3 4 500]
fmt.Println(ref) // [100 2 3 4 500]
}

操作

  • Slice 做一些操作
  • len 函式可以查長度
  • cap 可以查參考的陣列有多少容量
1
2
3
4
5
6
7
8
9
10
package main

import "fmt"

func main() {
slice := []int{1, 2, 3}

fmt.Println(len(slice)) // 3
fmt.Println(cap(slice)) // 3
}
  • append 函式可以追加新元素在 Slice 最後面
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
package main

import "fmt"

func main() {
slice1 := []int{1, 2, 3}

fmt.Println(slice1) // [1 2 3]
fmt.Println(len(slice1)) // 3
fmt.Println(cap(slice1)) // 3

slice2 := append(slice1, 10)

fmt.Println(slice2) // [1 2 3 10]
fmt.Println(len(slice2)) // 4
fmt.Println(cap(slice2)) // 6

slice3 := append(slice2, 20)

fmt.Println(slice3) // [1 2 3 10 20]
fmt.Println(len(slice3)) // 5
fmt.Println(cap(slice3)) // 6

slice3[0] = 100
fmt.Println(slice1) // [1 2 3]
fmt.Println(slice2) // [100 2 3 10]
fmt.Println(slice3) // [100 2 3 10 20]
}
  • slice1 加入新元素產生出 slice2 有發生長度與容量的變化(長度 + 1 ,容量 * 2),並且最後面 slice1slice2 的值沒有參考到同個陣列。

  • slice2 加入新元素產生出 slice3 只有長度 + 1 而已,最後面的值參考到同個陣列。

  • Slice 新增元素超過了容量的時候,它會產生新的陣列,且容量有兩倍,給新的 Slice 參考;而容量夠用的時候,則不會產生新陣列。

  • copy 函式可以複製內容到另一個 Slice

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
package main

import "fmt"

func main() {
src := []int{1, 2, 3}
dst1 := make([]int, 2)
dst2 := make([]int, 3)
dst3 := make([]int, 4)

fmt.Println(src) // [1 2 3]
fmt.Println(dst1) // [0 0]
fmt.Println(dst2) // [0 0 0]
fmt.Println(dst3) // [0 0 0 0]

copy(dst1, src)
copy(dst2, src)
copy(dst3, src)

fmt.Println(src) // [1 2 3]
fmt.Println(dst1) // [1 2]
fmt.Println(dst2) // [1 2 3]
fmt.Println(dst3) // [1 2 3 0]

src[0] = 100

fmt.Println(src) // [100 2 3]
fmt.Println(dst1) // [1 2]
fmt.Println(dst2) // [1 2 3]
fmt.Println(dst3) // [1 2 3 0]
}

  • 複製時,即使長度不一還是會執行成功,只是會沒有複製完全。

從陣列或 Slice 產生 Slice

  • 除了從頭建一個新的 Slice 外,也可以從陣列或 Slice 上產生新的 Slice
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
package main

import "fmt"

func main() {
arr := [...]int{1, 2, 3, 4, 5} // array

slice := arr[1:4]

fmt.Println(slice) // [2 3 4]
fmt.Println(len(slice)) // 3
fmt.Println(cap(slice)) // 4

slice2 := slice[1:3]

fmt.Println(slice2) // [3 4]
fmt.Println(len(slice2)) // 2
fmt.Println(cap(slice2)) // 3

slice2[0] = 300

fmt.Println(arr) // [1 2 300 4 5]
fmt.Println(slice) // [2 300 4]
fmt.Println(slice2) // [300 4 5]
}

  • [1:4] 代表的意思是,從**「第 1 個元素開始,到第 4 個元素,不含第 4 個元素」**,因此取得 [2 3 4] 三個元素。而容量會從第 1 個元素開始,一直到結尾。
  • [1:3] 會從 [2 3 4] 這個 Slice 取元素,所以取到的是 [3 4] ,容量是 3。
  • 因為沒有使用 append 函式,所以都參考到第一個陣列。
  • 另外也可以使用 [:] 來取得全部陣列的內容。