美文网首页
切片遍历的坑

切片遍历的坑

作者: 马晓钧 | 来源:发表于2020-06-17 17:11 被阅读0次

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

原理

  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的

相关文章

  • 切片遍历的坑

    我们正常对于一个切片进行遍历不会有啥坑的,会出现有坑的点是,在遍历的过程中想对原切片数据进行修改,其中包括修改原切...

  • day02-08make_slice

    make定义切片的长度和容量 切片的赋值 切片的遍历 索引遍历 for range循环

  • go的数组(切片)range遍历小坑

    原创文章转载请注明出处 go的数组元素可以通过 索引(位置)来读取(或者修改),索引从 0 开始,第一个元素索引为...

  • go切片遍历

    顺序遍历 对于切片的顺序遍历,一般使用range就可以了。 这里有一个问题需要注意一下,如果这里的切片nums不是...

  • 21. range用法

    range是一个内置函数。可以遍历数组、切片slice、字典map。当遍历数组和切片的时候,返回的是索引和元素。当...

  • Go 踩过的坑之协程 参数不能过大

    Go 踩过的坑之协程 参数不能过大 先知 问题重现 从mysql请求的切片数据,遍历后开启协程根据指定字段统计数据...

  • 大家一起学python(3)

    列表进阶 1.遍历列表 --- for...in 2.切片 -- 列表的子集 要创建切片就要明确索...

  • go学习笔记: range函数

    range函数是个神奇而有趣的内置函数,你可以使用它来遍历数组,切片和字典。 当用于遍历数组和切片的时候,rang...

  • goland中的for循环遍历

    给定值遍历 字符串遍历 数组的遍历 切片的遍历 也是两种,和数组差不多,这里只写第二种 map的遍历

  • Python列表操作:遍历、range()、列表解析、列表切片、

    列表操作:遍历、range()、列表解析、列表切片、列表复制、元组 1. 遍历列表 记得for ...... :有...

网友评论

      本文标题:切片遍历的坑

      本文链接:https://www.haomeiwen.com/subject/zgbsxktx.html