課程地址 go-class-slides/xmas-2020 at trunk · matt4biz/go-class-slides (github.com)
主講老師 Matt Holiday
10-Slices in Detail
Slice
package main
import "fmt"
func main() {
var s []int
t := []int{}
u := make([]int, 5)
v := make([]int, 0, 5)
fmt.Printf("%d, %d, %T, %5t %#[3]v\n", len(s), cap(s), s, s == nil)
fmt.Printf("%d, %d, %T, %5t %#[3]v\n", len(t), cap(t), t, t == nil)
fmt.Printf("%d, %d, %T, %5t %#[3]v\n", len(u), cap(u), u, u == nil)
fmt.Printf("%d, %d, %T, %5t %#[3]v\n", len(v), cap(v), v, v == nil)
}
0, 0, []int, true []int(nil)
0, 0, []int, false []int{}
5, 5, []int, false []int{0, 0, 0, 0, 0}
0, 5, []int, false []int{}

\(t\) 中的 \(addr\) 指向一個起哨兵作用的結構,所以我們知道它是空的而不是 \(nil\).
可以用 append 方法生成元素存盤地址,并回傳一個描述符參考這個存盤給 \(s\) . 即便 \(s\) 為 \(nil\)
Empty vs nil slice

使用 \(nil\) 、\(empty\) 映射替換切片在這個例子中分別是 null、{ } ,
判斷切片是否為空不能使用 a == nil ,因為有 \(nil\)、\(empty\) 兩種情況,應該用 len(a) 進行判斷,
最好make切片的時候給定 length,否則新建同長度容量的切片用append會將元素追加在一堆0的后面,
Important
package main
import "fmt"
func main() {
a := [3]int{1, 2, 3}
b := a[:1]
fmt.Println("a = ", a)
fmt.Println("b = ", b)
c := b[0:2]
fmt.Println("c = ", c)
fmt.Println(len(b))
fmt.Println(cap(b))
fmt.Println(len(c))
fmt.Println(cap(c))
d := a[0:1:1]
// e := d[0:2]
fmt.Println("d = ", d)
// fmt.Println("e = ", e) Error
fmt.Println(len(d))
fmt.Println(cap(d))
}
a = [1 2 3]
b = [1]
c = [1 2]
1
3
2
3
d = [1]
1
2
對截取的切片再次進行切片是根據原先的底層陣列來的,
如果你使用兩個索引切片符,你得到的切片的容量等于底層陣列的容量,
package main
import "fmt"
func main() {
a := [3]int{1, 2, 3}
b := a[:1]
// c := b[0:2]
c := b[0:2:2]
fmt.Printf("a[%p] = %v\n", &a, a)
fmt.Printf("b[%p] = %v\n", b, b)
fmt.Printf("c[%p] = %v\n", c, c)
c = append(c, 5)
fmt.Printf("a[%p] = %v\n", &a, a)
fmt.Printf("c[%p] = %v\n", c, c)
c[0] = 9
fmt.Printf("a[%p] = %v\n", &a, a)
fmt.Printf("c[%p] = %v\n", c, c)
}
a[0xc000010150] = [1 2 3]
b[0xc000010150] = [1]
c[0xc000010150] = [1 2]
a[0xc000010150] = [1 2 3]
c[0xc00000e2a0] = [1 2 5]
a[0xc000010150] = [1 2 3]
c[0xc00000e2a0] = [9 2 5]
\(a\) 是一個陣列,\(b、c\) 是兩個切片,它們指向 \(a\),
-
對 \(c\) 添加元素,會發現 \(a、c\) 被改變,\(c\) 的容量為 \(3\),長度為 \(2\),對 \(c\) 添加元素的時候把 \(a\) 修改了,覆寫 \(a\) 的第三個值,
-
對 \(c\) 限制容量數量,再添加元素會導致沒有地方放置,所以會重新分配一塊容量更大的記憶體區域,拷貝原先的元素,再把新加的元素放進去,底層陣列地址發生改變,
去掉 \(a\),將 \(b\) 宣告為切片并初始化,\(b\) 描述符指向無命名的底層陣列,用 \(c\) 對其切片,并添加元素,結果和上面是一樣的,切片實際上是一些底層陣列的別名,
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/456095.html
標籤:Go
