切片遍历的坑

我们正常对于一个切片进行遍历不会有啥坑的,会出现有坑的点是,在遍历的过程中想对原切片数据进行修改,其中包括修改原切片中某个值,对原切片增加元素,删除元素等。

原理

  1. 在range的时候,并不会对切片中的元素直接操作,而是新创建一块地址,然后把切片中每个元素的地址拷贝到这块新地址当中,这块地址在切片遍历期间不会发生任何变化。(核心点)
  2. 在range开始的时候,就会把长度记下来,期间不管这个切片发生了什么变化,都会遍历这么长。
  3. 在range过程中删除的时候,如果说index超出了切片的大小,会panic,在没有超出的情况下,删除几个元素,指针会向移动几位,即使是删除之前的元素,依然会向后移动。当后面没有元素了,但还在遍历中的时候,删除了几个元素,指针就会从后往前退几位,再重新进行遍历。即使在删除过程中新增的元素,永远也不会遍历到这个。


    image.png

场景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的

你可能感兴趣的:(切片遍历的坑)