2 回答
TA贡献1848条经验 获得超2个赞
问题在这里:
append(newSets, append(set, n))
问题不在于它是嵌套追加。问题是您假设append(set,n)将返回一个新切片。情况并非总是如此。切片是数组的视图,当您向切片添加新元素时,如果添加未导致数组重新分配,则返回的切片与您传入的切片相同,但len字段递增。因此,当您浏览结果数组时,您正在修改已经存在的元素,同时再次添加它们,就好像它们是不同的结果一样。
要解决这个问题,当您获得 的元素时result,创建一个新切片,将 的元素复制result到其中,追加新元素,然后将新切片添加到result.
TA贡献1798条经验 获得超7个赞
问题很简单:append接受一个切片参数[]T——对于某些类型T——当然还要加上要附加的元素,然后返回一个[]T结果。但是[]T,如果非零,则由两部分组成:指向某个后备数组并携带当前长度和容量的切片头,以及后备数组。它什么append时候工作,它有一个选择:
就地修改后备数组,并返回一个新的切片头,它重用现有的后备数组,或者
创建一个新的后备数组,将原始值复制到新的后备数组,并返回一个使用新后备数组的新切片头。
每当append 复制后备数组时,您的代码都会起作用。每当它重新使用后备数组时,您的代码可能会或可能不会工作,这取决于其他切片标头是否使用相同的后备数组。
例如,假设您的支持数组的长度为 5,并且现有切片标头之一读取“长度 1,容量 5”,支持数组的元素 0 为零。也就是说,现有的切片头h包含[0]. 现在你打电话append(h, 1)。追加操作重新使用后备数组并放入1第二个元素并返回一个新的切片头h1,其中包含[0, 1]. 现在你h 再次获取,追加2,并制作一个包含 的二元素h2切片[0, 2]。但这重用了与重用相同的支持数组,h1因此现在h1也适用[0, 2]。
要在不大量修改算法的情况下解决问题,您需要:
append总是复制的变体,或将一个 int 附加到始终复制的 int 切片的一种变体。
后者更简单:
func setPlusInt(set []int, n int) []int {
return append(append([]int(nil), set...), n)
}它使您可以替换现有代码的一行。
(我在这里做了另一个微不足道的更改,并添加了足够的内容以在 Go Playground 中提供一个工作示例。)
(另一种解决方案是设置您自己的每个切片标头以不提供额外容量,因此append必须始终复制。我没有说明这种方法。)
- 2 回答
- 0 关注
- 173 浏览
添加回答
举报
