当前位置:网站首页>[golang] how to clear slices gracefully
[golang] how to clear slices gracefully
2022-06-23 20:05:00 【DDGarfield】
This is an interesting question , Before that , Bloggers have never considered this issue , Until recently , After all, it's still with Empty the slice Met .
The scene is like this : Need to batch from influxdb Query data in , The query condition of this batch query is to traverse the field of a structure slice , constantly append, In order to avoid a large number of queries , Affecting query efficiency . The following processing is done on the code :
var queryIDs []int64
for _,v:= range vList{
queryIDs=append(queryIDs,v.ID)
if len(queryIDs)>50{
//omit query code
queryIDs=[]int64{}
}
}
if len(queryIDs) > 0 {
//omit query code
}
During traversal , When queryIDs Is longer than 50, Start the query now , After the query , Slice empty , After the traversal is over ,queryIDs There are still data , The rest of the query continues .
1. Method 1
Like the code above :
func main() {
sliceIntA := make([]int, 0, 50)
sliceIntA = append(sliceIntA, 1, 2, 3)
sliceIntA = []int{}
}
It's a way , But we want to know what happens to the slice ?
func main() {
sliceTestB := make([]int, 0, 50)
fmt.Printf("len of sliceIntA:%d,cap of sliceIntA:%d\n", len(sliceIntA), cap(sliceIntA))
sliceTestB = append(sliceTestB, 1, 2, 3)
fmt.Printf("len of sliceIntA:%d,cap of sliceIntA:%d\n", len(sliceIntA), cap(sliceIntA))
sliceTestB = []int{}
fmt.Printf("len of sliceIntA:%d,cap of sliceIntA:%d\n", len(sliceIntA), cap(sliceIntA))
}
len of sliceIntA:0,cap of sliceIntA:50
len of sliceIntA:3,cap of sliceIntA:50
len of sliceIntA:0,cap of sliceIntA:0
It can be seen that the slices emptied by this method , length len by 0, Capacity cap Also for the 0
2. Method 2
Go In language , The initial value of a type is called a zero value , Common Boolean values of type zero false, The zero value of a numeric type is 0, The zero value of the string type is an empty string "", and pointer、slice、map、channel、func and interface The zero value of is nil. So can we use nil To empty the slices ?
func main() {
array := [...]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
sliceIntB := array[2:6]
sliceIntB = nil
}
func main() {
array := [...]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
sliceIntB := array[2:6]
sliceIntB = nil
fmt.Printf("len of sliceIntB:%d,cap of sliceIntB:%d\n", len(sliceIntB), cap(sliceIntB))
}
len of sliceIntB:0,cap of sliceIntB:0
2.1 Is it the same ?
Look at the output , It seems that the effect of the above method is the same . Is this the case ?
We add the following code :
fmt.Printf("%p\n", sliceIntB) // Output 0x0
fmt.Println(sliceIntB==nil) //true
Look at the above method
fmt.Printf("%p\n", sliceIntA) // Output 0xb3fe00fmt.Println(sliceIntA==nil) //false
See? , In terms of the length and capacity of the slice , Both of these are empty slices , Both length and capacity belong to 0. Learn from bloggers go The beginning of language , I was told by my predecessors :
- To check if the slice is empty , Please always use len(s) == 0 To judge , Instead of using s == nil To judge .
- As above sliceIntA equally , Although it's an empty slice , But it's not zero .
- One nil The slice of values has no underlying array , But one nil The length and capacity of the slice of value are 0. But we can't say that a length and capacity are 0 The slice of must be nil;
- adopt
nilAfter emptying the slice , The slice does not point to the underlying array , If there is no other reference to the underlying array , If you're right , I'm afraid we can only rely onGCRecycled .
2.2 Then compare the differences
In order to see the difference of memory address more intuitively , We get the slice based on the array through the slice expression , And from 0 Start cutting , So you can get the same address .
func main() { array := [...]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10} sliceIntA := array[0:6] fmt.Printf("1.array %p\n", &array) fmt.Printf("2.sliceIntA %p\n", sliceIntA) fmt.Println(sliceIntA) sliceIntA = []int{} fmt.Printf("1.array %p\n", &array) fmt.Printf("2.sliceIntA %p\n", sliceIntA) sliceIntA = nil fmt.Printf("2.sliceIntA %p\n", sliceIntA) fmt.Printf("1.array %p\n", &array) sliceIntA = append(sliceIntA, 1) fmt.Printf("2.sliceIntA %p\n", sliceIntA)}
1.array 0xc00000c1e02.sliceIntA 0xc00000c1e0[1 2 3 4 5 6]1.array 0xc00000c1e0# Empty method 1 2.sliceIntA 0x108de00# Empty method 2 2.sliceIntA 0x01.array 0xc00000c1e0# append2.sliceIntA 0xc0000120d0
It can be seen that :
- Use method 1. After emptying , The underlying array pointed to by the slice has changed , The original underlying array remains unchanged , Therefore, operate the slice again at this time , It will not affect the original underlying array ;
- Use
nilAfter emptying , The slice has no underlying array ,appendafter , It points to the new underlying array , The original underlying array remains unchanged ;
It can be concluded that : The above emptying method , Will cause the underlying array to be replaced .
3. A more elegant way
It seems that the above has met our need to empty the slice , But there will be the following problems :
- Continue when you need to empty append In case of operation , Will cause the underlying array to be replaced , Open up new space , I'm afraid the original underlying array depends on GC Recycled ;
- After the slice is empty , Except for the length 0, Capacity also belongs to 0 了 , This is actually not conducive to our follow-up
append, Because when the length is about to exceed the capacity , The capacity will be expanded according to the expansion strategy .
There will be a performance problem with both of the above problems , In most cases , We can ignore , however , We still have to ask : Is there a more elegant way to empty the slice ?
func main() { array := [...]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10} sliceIntA := array[0:6] fmt.Printf("array %p\n", &array) fmt.Printf("sliceIntA %p\n", sliceIntA) fmt.Println(array) fmt.Println(sliceIntA) fmt.Printf("len of sliceIntA:%d,cap of sliceIntA:%d\n", len(sliceIntA), cap(sliceIntA)) sliceIntA = sliceIntA[0:0] fmt.Printf("array %p\n", &array) fmt.Printf("sliceIntA %p\n", sliceIntA) fmt.Println(sliceIntA) fmt.Println(array) fmt.Printf("len of sliceIntA:%d,cap of sliceIntA:%d\n", len(sliceIntA), cap(sliceIntA))}
array 0xc00000c1e0sliceIntA 0xc00000c1e0[1 2 3 4 5 6 7 8 9 10][1 2 3 4 5 6]len of sliceIntA:6,cap of sliceIntA:10# After emptying array 0xc00000c1e0sliceIntA 0xc00000c1e0[][1 2 3 4 5 6 7 8 9 10]len of sliceIntA:0,cap of sliceIntA:10
By output , We can easily draw the following conclusion :
- adopt Slice expression empty section , Length only 0, And the capacity remains the same
- Solved the problem of possible capacity expansion
- After emptying , The underlying array pointed to by the slice is also unchanged
- Solved the problem of replacing the underlying array , Open up new space , And possible garbage collection problems
Be careful : The underlying array pointed to by the slice remains unchanged , This leads to both slicing and array operations , Will affect each other .
sliceIntA = append(sliceIntA, 999) // After the slice is empty append value sliceIntA = append(sliceIntA, 888) // After the slice is empty append value fmt.Printf("array %p\n", &array)fmt.Printf("sliceIntA %p\n", sliceIntA)fmt.Println(sliceIntA) //[999 888]fmt.Println(array) //[999 888 3 4 5 6 7 8 9 10]fmt.Printf("len of sliceIntA:%d,cap of sliceIntA:%d\n", len(sliceIntA), cap(sliceIntA))array[0]=777 // Modify the value through the array index fmt.Printf("array %p\n", &array)fmt.Printf("sliceIntA %p\n", sliceIntA)fmt.Println(sliceIntA) // [777 888]fmt.Println(array) //[777 888 3 4 5 6 7 8 9 10]fmt.Printf("len of sliceIntA:%d,cap of sliceIntA:%d\n", len(sliceIntA), cap(sliceIntA))
array 0xc00000c1e0sliceIntA 0xc00000c1e0[999 888][999 888 3 4 5 6 7 8 9 10]len of sliceIntA:2,cap of sliceIntA:10array 0xc00000c1e0sliceIntA 0xc00000c1e0[777 888][777 888 3 4 5 6 7 8 9 10]len of sliceIntA:2,cap of sliceIntA:10
see , Modifying the slice affects the array , Modifying the array will affect the slice , until Slice length is about to exceed capacity , Replace the underlying array , The two of them will decouple , This conclusion , Please move to another blog post 【Golang】 A few questions to strengthen Slice
4. Conclusion
There are 3 A way to empty slices , But their essence is different , There are no extreme requirements for performance , Can be used , If there are other special needs , Be sure to keep in mind whether the bottom layer array is replaced , Please use with care . Of course , If you just empty the slice , Go ahead append operation , Bloggers recommend slicing expressions [0:0].
------------------- End -------------------
边栏推荐
- What are the requirements for new bonds? Is it safe to play new bonds
- I came from a major, so I didn't want to outsource
- 【白话技术】二维码
- [golang] quick review guide quickreview (VI) -- struct
- 【Golang】在Go语言的角度重新审视闭包
- ZABBIX monitoring - Aruba AP operation data
- Deep learning of handlebar handwriting (15): building your own corpus on hugging face
- 技术分享| WVP+ZLMediaKit实现摄像头GB28181推流播放
- Zabbix监控- Aruba AP运行数据
- The "open source star picking program" container pulls private images from harbor, which is a necessary skill for cloud native advanced technology
猜你喜欢
随机推荐
Elastricearch's fragmentation principle of the second bullet
Interpreting the 2022 agile coaching industry status report
Game asset reuse: a new way to find required game assets faster
Save: software analysis, verification and test platform
What are the requirements for new bonds? Is it safe to play new bonds
【Golang】类型转换归纳总结
TCP/UDP基本原理
Leaders of Hangcheng street, Bao'an District and their delegation visited lianchengfa for investigation
【Golang】快速复习指南QuickReview(六)——struct
科班出身,结果外包都不要
墨天轮访谈 | IvorySQL王志斌—IvorySQL,一个基于PostgreSQL的兼容Oracle的开源数据库
为什么你的数据图谱分析图上只显示一个值?
[cloud trends] the four highlights of Huawei cloud store brand new release are here
UGeek大咖说 | 可观测之超融合存储系统的应用与设计
【Golang】快速复习指南QuickReview(十)——goroutine池
Kubernetes 资源拓扑感知调度优化
Flagai Feizhi: AI basic model open source project, which supports one click call of OPT and other models
QGIS import WMS or WMTs
【Golang】在Go语言的角度重新审视闭包
LeetCode 260. 只出现一次的数字 III









