对slice高效的过滤
利用slice的特性,我们在过滤并删除slice的数据不必要在重新make一个新的slice因为这样会重新创建数组浪费空间。所以最好借用原来的slice在原来的slice基础上创建slice,这样在删除时底层不会重新创建数组。
func Filter(s []byte, fn func(x byte) bool) []byte {
b:=s[:0] //我们利用传过来的slice重新创建一个slice,底层不会重新创建数组
for _, x := range s {
if !fn(x) {
b = append(b, x)
}
}
return b
}
slice逃逸
demo1
例如, getData函数加载整个文件到内存,返回从index开始以后的数据。
func getData(path string,index int)[]byte{
if
b, err := ioutil.ReadFile(filename)//加载整个文件
if err!=nil{
fmt.Println(err.Error())
return nil
}
return b[index:] // 返回从index开始的数据
}
该代码查找到对应的数据后直接返回原slice,由于存放原数据的slice被别的函数引用,那么该slice会被放到堆内存中而不是随着函数结束而被释放的栈内存。这样时间长就会对整个系统性能产生影响。
要修复这个问题,可以将需要的数据的数据复制到一个新的切片中返回即可,这样会节省堆内存[0:index]这么多的空间。
func getData(path string,index int)[]byte{
if
b, err := ioutil.ReadFile(filename)//加载整个文件
if err!=nil{
fmt.Println(err.Error())
return nil
}
return appen([]byte{},b[index:]...) // 返回从index开始的数据
}
demo2
如果slice里面保存的是指针类型的数据,要删除slice里面的数据,如果slice底层数组还在被引用,那么被删除的元素空间是不会被释放的
// 删除最后一个元素
func del(arr []*int)[]*int{
arr = arr[:len(arr)-1] // 删除最后一个元素
return arr
}
这样做最后一个元素对应的值得内存空间不会被释放,因为底层数组根本没动依旧保存着最后一个值对应的地址。
正确做法:
// 删除最后一个元素
func del(arr []*int)[]*int{
arr[len(arr)-1]=nil // 取消底层数组和最后一个元素的联系,使得gc回收
arr = arr[:len(arr)-1] // 删除最后一个元素
return arr
}