当我尝试循环切片并删除序列中的每个元素以打印其余元素时,我会使用SliceTricks中建议的删除方法获得一些意外行为。例如,当我尝试循环包含字母[A B C]
的切片时,我希望输出按顺序为[B C]
,[A C]
,[A B]
:
方法1
package main
import "fmt"
func main() {
a := []string {"A", "B", "C"}
for i, _ := range a {
fmt.Println(append(a[:i], a[i+1:]...))
}
}
然而,这里的输出对我来说是令人惊讶的。它输出[B C]
三次。
通过执行以下操作,我最终得到了预期的行为:
方法2
package main
import "fmt"
func main() {
a := []string {"A", "B", "C"}
for i, _ := range a {
result := make([]string, 0)
result = append(result, a[:i]...)
result = append(result, a[i+1:]...)
fmt.Println(result)
}
}
在方法1中导致意外行为的原因是什么,除了方法2之外还有更好的方法来实现这个目标吗?
答案 0 :(得分:5)
如果您想在没有额外分配的情况下执行此操作,请尝试更换显示的值in this example:
请注意,这假设您可以随机播放列表内容。 如果没有,只需在循环之前复制一次列表,并执行以下操作。
package main
import "fmt"
func main() {
set := []string{"a", "b", "c"}
for i := range set {
set[0], set[i] = set[i], set[0]
fmt.Println(set[1:])
}
}
输出:
[b c]
[a c]
[a b]
答案 1 :(得分:1)
“what”是因为append(slice, elems...)
实际上是用新元素更新slice
。它返回一个“新”切片只是因为它可能由于内存重新分配而不得不重新定位原始切片。因此,在您的示例代码中,您实际上每次调用a
时都会更改append
的内容。 (好的概述在this golang博客文章的“附加:示例”部分中。)
关于“如何”,我的尝试是:
package main
import "fmt"
func main() {
a := []string {"A", "B", "C"}
for i, _ := range a {
result := make([]string, i, len(a)-1)
copy(result, a[:i])
result = append(result, a[i+1:]...)
fmt.Println(result)
}
}
使用长度和容量初始化result
,以及使用copy
而不是两次append
s尝试减少所需的内存重新分配次数。
答案 2 :(得分:0)
看看第一次迭代后会发生什么:
package main
import "fmt"
func main() {
a := []string{"A", "B", "C"}
x := append(a[:0], a[1:]...)
fmt.Println(a)
fmt.Println(x)
}
给予
[B C C]
[B C]
请参阅https://play.golang.org/p/2LqBwHejhy
接下来的两次迭代是相似的。试试吧。