Go基础数据结构学习——slice
slice
-
Slice切片:是一个数组某部分的引用,在内存中是一个包含三个域的结构体,第一个是指向数据的第一个元素的指针,第二个是切片的长度,第三个是切片的容量
type slice struct { array unsafe.Pointer len int cap int }
-
slice不能简单使用==来测试两个slice是否拥有相同的元素,对于引用类型,操作符==检查的是引用相等性,即是否指向相同的元素。如果切片类型是字节([]byte),可以使用bytes.Equal比较,其他的类型就不可以了。slice唯一允许的比较操作就是和nil做比较。
func Equal(a, b []string) bool { if len(a) != len(b){ return false } for i := range a{ if a[i] != b[i]{ return false } } return true }
-
注意:
-
slice的零值是nil
-
值为nil的slice长度和容量都是0
var s []string // len(s) == 0,s == nil s = nil // len(s) == 0,s == nil s = []string(nil) // len(s) == 0,s == nil s = []string{} // len(s) == 0,s != nil s = make([]string, 3) // len(s) == 0,s != nil
检查slice是否是空可以使用len(s) == 0而不是s == nil,s为nil也可能为空
-
重新切分切片不会复制底层数组
-
make([]T, len) 和make([]T, len, cap):初始化的时候如果使用make([]T, 3) 的含义是len=3,且 cap=3的数组,此时数组中已经存在3个nil的元素了,如果使用make([]T, 0, 3)含义是len=0,cap=3的数组,数组中为空
-
数组是值拷贝而切片是引用
-
-
slice的扩充:每次调用都必须检查slice是否有足够的容量来存储数组中的新元素,
-
如果slice容量足够,他就会定义一个新的slice,仍然应用原始底层数组,然后将新元素复制到新的位置并返回新的slice;
-
如果新的大小是当前大小的两倍以上,则大小为新大小
-
如果当前大小小于1024,按每次两倍增长,否则按当前大小四分之一增长,知道增长的大小超过或等于新大小
// runtime/slice.go func growslice(et *_type, old slice, cap int) slice { // ......省略 newcap := old.cap doublecap := newcap + newcap if cap > doublecap { newcap = cap } else { if old.len < 1024 { newcap = doublecap } else { // Check 0 < newcap to detect overflow // and prevent an infinite loop. for 0 < newcap && newcap < cap { newcap += newcap / 4 } // Set newcap to the requested cap when // the newcap calculation overflowed. if newcap <= 0 { newcap = cap } } } // ......省略 }
-