关于 Golang 中 range 的使用

2019-10-24 16:24:37 +08:00
 KaynW
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

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

3198 次点击
所在节点    Go 编程语言
10 条回复
xta
2019-10-24 16:28:00 +08:00
dd
KaynW
2019-10-24 16:43:46 +08:00
我们遇到什么困难,都不要怕,微笑着面对它,消除恐惧的最好办法就是面对恐惧,加油,奥利给!
l1nyanm1ng
2019-10-24 16:48:40 +08:00
@KaynW 你少了一句“坚持,才是胜利”
baiyi
2019-10-24 17:01:05 +08:00
我记得 go range 的 value 是值引用,那 key 是不是也是这样

猜测:range 不是创建的副本,而是获取了长度
maichael
2019-10-24 17:31:49 +08:00
你这里的正确只是碰巧正确而已,你可以把 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
2019-10-24 17:37:52 +08:00
@maichael 我佛了, 我就随便测试一个结果还是碰巧对了,什么鬼运气,我去好好瞅瞅
KaynW
2019-10-24 17:48:43 +08:00
@maichael 那对于这种需求有什么优雅的解决方法没,现在能想到的只有自己写个 index 方法或者单独起个数组记录需要删除的元素
maichael
2019-10-24 18:00:55 +08:00
@KaynW #7 你这是 filter 的需求,可以参考这个 https://github.com/golang/go/wiki/SliceTricks#filtering-without-allocating,其实就是用切片而不是用数组,由于切片是共享同一个 “backing array”,所以不会有额外的消耗。
maichael
2019-10-24 18:01:19 +08:00
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

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/612595

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX