切片踩坑:https://blog.csdn.net/a775189488/article/details/114278113
切片技巧:https://www.liwenzhou.com/posts/Go/slice_tricks/
截取
s = s[low : high : max]
low为截取的起始下标(含),
high为窃取的结束下标(不含high),
max为切片保留的原切片的最大下标(不含max)
即新切片从老切片的low下标元素开始,len = high - low, cap = max - low;
high 和 max一旦超出在老切片中越界,就会发生runtime err,slice out of range。
另外如果省略第三个参数的时候,第三个参数默认和第二个参数相同,即len = cap (这条不准确)
s := []int{1, 1, 1, 1, 1}
s1 := s[1:3]
fmt.Println(s1)
fmt.Println(len(s1)) // 2
fmt.Println(cap(s1)) // 4
s := []int{1, 1, 1, 1, 1}
s1 := s[1:3:4]
fmt.Println(s1)
fmt.Println(len(s1)) // 2
fmt.Println(cap(s1)) // 3
不会改变原数组 s
func myAppend(s []int) []int {
s = append(s, 100)
return s
}
会改变原数组 s
func myAppendPtr(s *[]int) {
// 会改变外层 s 本身
*s = append(*s, 100)
return
}
拷贝
b := make([]int, 4)
copy(b, a)
b := make([]int, 0 , 4)
copy(b, a) //这种没效果
// 拷贝方式比较慢,不过添加元素比较快
b = append([]T(nil), a...)
b = append(a[:0:0], a...)
剪切或删除操作可能引起的内存泄露
需要特别注意的是。如果切片a中的元素是一个指针类型或包含指针字段的结构体类型(需要被垃圾回收),
普通的剪切和删除的代码会存在一个潜在的内存泄漏问题:一些具有值的元素仍被切片a引用,因此无法被垃圾回收机制回收掉。
下面的代码可以解决这个问题
// 剪切
copy(a[i:], a[j:])
for k, n := len(a)-j+i, len(a); k < n; k++ {
a[k] = nil // 或类型T的零值
}
a = a[:len(a)-j+i]
// 删除
copy(a[i:], a[i+1:])
a[len(a)-1] = nil // 或类型T的零值
a = a[:len(a)-1]
过滤
// 这代码是真的骚,牛啊
n := 0
for _, x := range a {
if keep(x) {
a[n] = x // 保留该元素
n++
}
}
a = a[:n] // 截取切片中需保留的元素
扩容策略
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 {
for 0 < newcap && newcap < cap {
newcap += newcap / 4
}
if newcap <= 0 {
newcap = cap
}
}
}
}