课程地址 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.cnblogs.com/linxiaoxu/p/16102314.html
本站部分图文来源于网络,如有侵权请联系删除。