我们正常对于一个切片进行遍历不会有啥坑的,会出现有坑的点是,在遍历的过程中想对原切片数据进行修改,其中包括修改原切片中某个值,对原切片增加元素,删除元素等。
原理
- 在range的时候,并不会对切片中的元素直接操作,而是新创建一块地址,然后把切片中每个元素的地址拷贝到这块新地址当中,这块地址在切片遍历期间不会发生任何变化。(核心点)
- 在range开始的时候,就会把长度记下来,期间不管这个切片发生了什么变化,都会遍历这么长。
-
在range过程中删除的时候,如果说index超出了切片的大小,会panic,在没有超出的情况下,删除几个元素,指针会向移动几位,即使是删除之前的元素,依然会向后移动。当后面没有元素了,但还在遍历中的时候,删除了几个元素,指针就会从后往前退几位,再重新进行遍历。即使在删除过程中新增的元素,永远也不会遍历到这个。
场景1:range过程中修改元素
切片中是非指针
修改e中的值,并不会改变原来切片中的值。
func main() {
num0 := 0
num1 := 1
num2 := 2
num3 := 3
slice := []int{num0, num1, num2, num3}
for _, v := range slice {
if v == 1 {
v = 100
}
}
for k, v := range slice {
fmt.Println("k:", k, "v:", v)
}
}
k: 0 v: 0
k: 1 v: 1
k: 2 v: 2
k: 3 v: 3
切片中是指针或结构体
func main() {
num0 := 0
num1 := 1
num2 := 2
num3 := 3
slice := []*int{&num0, &num1, &num2, &num3}
for _, v := range slice {
if *v == 1 {
*v = 100
}
}
for k, v := range slice {
fmt.Println("k:", k, "v:", *v)
}
}
k: 0 v: 0
k: 1 v: 100
k: 2 v: 2
k: 3 v: 3
场景2:新增元素
append
func main() {
num0 := 0
num1 := 1
num2 := 2
num3 := 3
slice := []int{num0, num1, num2, num3}
for _, v := range slice {
fmt.Println(v)
if v == 2 {
slice = append(slice, 4)
}
}
for k, v := range slice {
fmt.Println("k:", k, "v:", v)
}
}
0
1
2
3
k: 0 v: 0
k: 1 v: 1
k: 2 v: 2
k: 3 v: 3
k: 4 v: 4
赋新值
func main() {
num0 := 0
num1 := 1
num2 := 2
num3 := 3
slice := []int{num0, num1, num2, num3}
for _, v := range slice {
fmt.Println(v)
if v == 2 {
slice = []int{5, 6, 7, 8}
}
}
for k, v := range slice {
fmt.Println("k:", k, "v:", v)
}
}
0
1
2
3
k: 0 v: 5
k: 1 v: 6
k: 2 v: 7
k: 3 v: 8
赋空
func main() {
num0 := 0
num1 := 1
num2 := 2
num3 := 3
slice := []int{num0, num1, num2, num3}
for _, v := range slice {
fmt.Println(v)
if v == 2 {
slice = nil
}
}
for k, v := range slice {
fmt.Println("k:", k, "v:", v)
}
}
0
1
2
3
场景3:删除元素
删除切片index内的元素
func main() {
num0 := 0
num1 := 1
num2 := 2
num3 := 3
num4 := 4
num5 := 5
slice := []*int{&num0, &num1, &num2, &num3, &num4, &num5}
for _, v := range slice {
fmt.Println(*v)
if *v == 0 {
//删除前三位
slice = append(slice[:0], slice[3:]...)
}
}
for k, v := range slice {
fmt.Println("k:", k, "v:", *v)
}
}
0
4
5
3
4
5
k: 0 v: 3
k: 1 v: 4
k: 2 v: 5
删除切片index外的元素
func main() {
num0 := 0
num1 := 1
num2 := 2
num3 := 3
num4 := 4
num5 := 5
slice := []*int{&num0, &num1, &num2, &num3, &num4, &num5}
for _, v := range slice {
fmt.Println(*v)
if *v == 0 {
//删除第10位
slice = append(slice[:10], slice[11:]...)
}
}
for k, v := range slice {
fmt.Println("k:", k, "v:", *v)
}
}
//直接panic的