V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
The Go Programming Language
http://golang.org/
Go Playground
Go Projects
Revel Web Framework
KaynW
V2EX  ›  Go 编程语言

关于 Golang 中 range 的使用

  •  
  •   KaynW · 2019-10-24 16:24:37 +08:00 · 3310 次点击
    这是一个创建于 1892 天前的主题,其中的信息可能已经有所发展或是发生改变。
    func main() {  
    	var a []int  
    	a = append(a, 1, 2)  
    	for _, _ = range a {  
    		a = append(a, 1)  
    	}  
    	fmt.Println(a)  
    }
    

    这个时候 range 不会无限循环,说明 range 在循环之前就创建了 a 的副本,a 的改动不会影响 range 的执行。(这一段持不肯定态度)

    然后

    func main() {  
        var a []int  
        a = append(a, 1, 2, 3, 4, 5, 4, 6, 6)  
    	for i, t := range a {  
            if t == 4 }  
                a = append(a[:i], a[i+1:]...)  
            }  
        }  
        fmt.Println(a)  
    } 
    

    如果 range 提前保存了 a 的副本,a 中含有两个 4,第一次可以正确删除 4,第二次删除 4 的时候 i 的值应该为 a 的副本中的下标,应该会删除错误的数字,但事实是 go 正确的删除了两个 4

    有没有人给小弟解个惑,纠结半天了

    第 1 条附言  ·  2019-10-24 17:39:47 +08:00
    a = append(a, 1, 2, 3, 4, 4, 4, 6, 6)

    三个 4 就会错了,我太难了
    xta
        1
    xta  
       2019-10-24 16:28:00 +08:00   ❤️ 1
    dd
    KaynW
        2
    KaynW  
    OP
       2019-10-24 16:43:46 +08:00   ❤️ 2
    我们遇到什么困难,都不要怕,微笑着面对它,消除恐惧的最好办法就是面对恐惧,加油,奥利给!
    l1nyanm1ng
        3
    l1nyanm1ng  
       2019-10-24 16:48:40 +08:00
    @KaynW 你少了一句“坚持,才是胜利”
    baiyi
        4
    baiyi  
       2019-10-24 17:01:05 +08:00
    我记得 go range 的 value 是值引用,那 key 是不是也是这样

    猜测:range 不是创建的副本,而是获取了长度
    maichael
        5
    maichael  
       2019-10-24 17:31:49 +08:00   ❤️ 2
    你这里的正确只是碰巧正确而已,你可以把 a = append(a, 1, 2, 3, 4, 5, 4, 6, 6) 改成 a = append(a, 1, 2, 3, 4, 4, 4, 6, 6) 试试。

    而且根据 https://golang.org/ref/spec#For_statements 里的 “For statements with range clause” 的第一种情况的说明,range 并不会索引到数组或者切片,而是索引到数组或切片的元素。

    而不会无线循环的原因来源于这一句:“The range expression x is evaluated once before beginning the loop, with one exception: if at most one iteration variable is present and len(x) is constant, the range expression is not evaluated.”
    KaynW
        6
    KaynW  
    OP
       2019-10-24 17:37:52 +08:00
    @maichael 我佛了, 我就随便测试一个结果还是碰巧对了,什么鬼运气,我去好好瞅瞅
    KaynW
        7
    KaynW  
    OP
       2019-10-24 17:48:43 +08:00
    @maichael 那对于这种需求有什么优雅的解决方法没,现在能想到的只有自己写个 index 方法或者单独起个数组记录需要删除的元素
    maichael
        8
    maichael  
       2019-10-24 18:00:55 +08:00   ❤️ 2
    @KaynW #7 你这是 filter 的需求,可以参考这个 https://github.com/golang/go/wiki/SliceTricks#filtering-without-allocating,其实就是用切片而不是用数组,由于切片是共享同一个 “backing array”,所以不会有额外的消耗。
    reus
        10
    reus  
       2019-10-24 18:45:40 +08:00
    slice 其实就是一个 struct,range 语句会复制这个 struct,而不是存放元素的 array,所以修改 slice 只是修改另一个 struct,对 range 所用的 struct 没有影响。
    但是两个 struct 可能用到同一个 array,也可能用不同的 array,因为 append 可能扩容
    删除 slice 里的特定元素有好几种方法,具体看: https://github.com/golang/go/wiki/SliceTricks
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2644 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 591ms · UTC 06:34 · PVG 14:34 · LAX 22:34 · JFK 01:34
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.