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
xta 2019-10-24 16:28:00 +08:00 1
dd
|
2
KaynW OP 我们遇到什么困难,都不要怕,微笑着面对它,消除恐惧的最好办法就是面对恐惧,加油,奥利给!
|
3
l1nyanm1ng 2019-10-24 16:48:40 +08:00
@KaynW 你少了一句“坚持,才是胜利”
|
4
baiyi 2019-10-24 17:01:05 +08:00
我记得 go range 的 value 是值引用,那 key 是不是也是这样
猜测:range 不是创建的副本,而是获取了长度 |
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.” |
7
KaynW OP @maichael 那对于这种需求有什么优雅的解决方法没,现在能想到的只有自己写个 index 方法或者单独起个数组记录需要删除的元素
|
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”,所以不会有额外的消耗。
|
9
maichael 2019-10-24 18:01:19 +08:00
|
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 |