百木园-与人分享,
就是让自己快乐。

Go xmas2020 学习笔记 10、Slices in Detail

课程地址 go-class-slides/xmas-2020 at trunk · matt4biz/go-class-slides (github.com)

主讲老师 Matt Holiday

image-20220401081031592

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{}

image-20220405134013956

\\(t\\) 中的 \\(addr\\) 指向一个起哨兵作用的结构,所以我们知道它是空的而不是 \\(nil\\).

可以用 append 方法生成元素存储地址,并返回一个描述符引用这个存储给 \\(s\\) . 即便 \\(s\\)\\(nil\\)

Empty vs nil slice

image-20220405134702334

使用 \\(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
本站部分图文来源于网络,如有侵权请联系删除。

未经允许不得转载:百木园 » Go xmas2020 学习笔记 10、Slices in Detail

相关推荐

  • 暂无文章