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 关注
- 151 浏览
添加回答
举报