Golang切片追加异常

huangapple go评论80阅读模式
英文:

Golang slice append exception

问题

这是一个LeetCode问题,当我尝试用下面的代码回答时:

package main

import "fmt"

func main() {
	nums := []int{9, 0, 3, 5, 7}
	fmt.Println(subsets(nums))
}

func subsets(nums []int) [][]int {
    var result [][]int
    result = append(result, []int{})
    for _, v := range(nums) {
        for _, rv := range(result) {
            result = append(result, append(rv, v))
        }
    }
    return result
}

LeetCode告诉我答案错误:

Wrong Answer
Details 
Input
[9,0,3,5,7]
Output
[[],[9],[0],[9,0],[3],[9,3],[0,3],[9,0,3],[5],[9,5],[0,5],[9,0,5],[3,5],[9,3,5],[0,3,5],[9,0,3,7],[7],[9,7],[0,7],[9,0,7],[3,7],[9,3,7],[0,3,7],[9,0,3,7],[5,7],[9,5,7],[0,5,7],[9,0,5,7],[3,5,7],[9,3,5,7],[0,3,5,7],[9,0,3,7,7]]
Expected
[[],[9],[0],[0,9],[3],[3,9],[0,3],[0,3,9],[5],[5,9],[0,5],[0,5,9],[3,5],[3,5,9],[0,3,5],[0,3,5,9],[7],[7,9],[0,7],[0,7,9],[3,7],[3,7,9],[0,3,7],[0,3,7,9],[5,7],[5,7,9],[0,5,7],[0,5,7,9],[3,5,7],[3,5,7,9],[0,3,5,7],[0,3,5,7,9]]

输出的切片索引15应该是[9,0,3,5],与期望的结果相同,但实际结果是[9,0,3,7]。
所以我尝试在Go Playground在线运行这段代码,结果也是错误的。然后我在Goland中以调试模式运行这段代码,我发现当我执行append([9,0,3], 7)时,输出切片的索引15同时改变。

我的本地Go环境:go version go1.17.6 windows/amd64

我只是一个刚开始学习Go的初学者,有人能解释一下这种情况吗?
非常感谢。

附注:我尝试使用下面的代码来复现同样的问题,但失败了。

package main

import "fmt"

func main() {
	a := [][]int{{}, {9}, {0}, {9, 0}, {3}, {9, 3}, {0, 3}, {9, 0, 3}, {5}, {9, 5}, {0, 5}, {9, 0, 5}, {3, 5}, {9, 3, 5}, {0, 3, 5}, {9, 0, 3, 5}}
	i := 7
	for _, v := range a {
		// fmt.Println(a)
		a = append(a, append(v, i))
		// fmt.Println(a)
	}
	fmt.Println(a)
}

结果
[[] [9] [0] [9 0] [3] [9 3] [0 3] [9 0 3] [5] [9 5] [0 5] [9 0 5] [3 5] [9 3 5] [0 3 5] [9 0 3 5] [7] [9 7] [0 7] [9 0 7] [3 7] [9 3 7] [0 3 7] [9 0 3 7] [5 7] [9 5 7] [0 5 7] [9 0 5 7] [3 5 7] [9 3 5 7] [0 3 5 7] [9 0 3 5 7]]
英文:

This is a leet code problem, and when I try to answer with the code blew:

package main

import "fmt"

func main() {
	nums := []int{9, 0, 3, 5, 7}
	fmt.Println(subsets(nums))
}

func subsets(nums []int) [][]int {
    var result [][]int
    result = append(result, []int{})
    for _, v := range(nums) {
        for _, rv := range(result) {
            result = append(result, append(rv, v))
        }
    }
    return result
}

Leetcode told me wrong answer:

Wrong Answer
Details 
Input
[9,0,3,5,7]
Output
[[],[9],[0],[9,0],[3],[9,3],[0,3],[9,0,3],[5],[9,5],[0,5],[9,0,5],[3,5],[9,3,5],[0,3,5],[9,0,3,7],[7],[9,7],[0,7],[9,0,7],[3,7],[9,3,7],[0,3,7],[9,0,3,7],[5,7],[9,5,7],[0,5,7],[9,0,5,7],[3,5,7],[9,3,5,7],[0,3,5,7],[9,0,3,7,7]]
Expected
[[],[9],[0],[0,9],[3],[3,9],[0,3],[0,3,9],[5],[5,9],[0,5],[0,5,9],[3,5],[3,5,9],[0,3,5],[0,3,5,9],[7],[7,9],[0,7],[0,7,9],[3,7],[3,7,9],[0,3,7],[0,3,7,9],[5,7],[5,7,9],[0,5,7],[0,5,7,9],[3,5,7],[3,5,7,9],[0,3,5,7],[0,3,5,7,9]]

The output slice index 15, it should be [9,0,3,5] like the expected, but the result is [9,0,3,7].
So I try to run this code by go playgroud online,the answer is the same wrong, and then I run this code in goland with debug mode,I find when I make the slice append([9,0,3], 7), the output slice index 15 change at the same time.

My local go env: go version go1.17.6 windows/amd64

I'm just a beginner to golang, could anyone explain this situation?
Thank you very much.

ps: I try to use blew code to recover same issue, but I failed.

package main

import "fmt"

func main() {
	a := [][]int{{}, {9}, {0}, {9, 0}, {3}, {9, 3}, {0, 3}, {9, 0, 3}, {5}, {9, 5}, {0, 5}, {9, 0, 5}, {3, 5}, {9, 3, 5}, {0, 3, 5}, {9, 0, 3, 5}}
	i := 7
	for _, v := range a {
		// fmt.Println(a)
		a = append(a, append(v, i))
		// fmt.Println(a)
	}
	fmt.Println(a)
}

result:
[[] [9] [0] [9 0] [3] [9 3] [0 3] [9 0 3] [5] [9 5] [0 5] [9 0 5] [3 5] [9 3 5] [0 3 5] [9 0 3 5] [7] [9 7] [0 7] [9 0 7] [3 7] [9 3 7] [0 3 7] [9 0 3 7] [5 7] [9 5 7] [0 5 7] [9 0 5 7] [3 5 7] [9 3 5 7] [0 3 5 7] [9 0 3 5 7]]

答案1

得分: 0

你在一些切片中重复使用了相同的后备数组,因为如果还有剩余容量,append函数就会这样做。一个简单的修复方法是将append(rv, v)替换为append(append([]int{}, rv...), v),从而创建一个全新的切片。另一种方法是通过将切片的容量限制为其当前长度,强制append函数分配一个新的后备数组:append(rv[:len(rv):len(rv)], v)

带有可工作代码的 Playground 链接:https://go.dev/play/p/Gc-yF5KQOAO

英文:

You are reusing the same backing array in some of your slices, because that's what append does if there's capacity remaining. A simple fix is to replace append(rv, v) with append(append([]int{}, rv...), v), creating an entirely new slice. An alternative is to force the append to allocate a fresh backing array by capping the slice to its current length: append(rv[:len(rv):len(rv)], v).

Playground link with working code: https://go.dev/play/p/Gc-yF5KQOAO

huangapple
  • 本文由 发表于 2022年2月13日 19:11:04
  • 转载请务必保留本文链接:https://go.coder-hub.com/71100078.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定