首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >被覆盖的Go变量(bug?)

被覆盖的Go变量(bug?)
EN

Stack Overflow用户
提问于 2013-11-29 02:07:52
回答 1查看 2.3K关注 0票数 4

所以这里有点奇怪。我的问题是,人们从运行我的代码得到的结果和我一样吗?如果是这样的话,这是我的代码的错误(我通常是python程序员),还是golang中的一个bug?

系统信息: Go版本(1.1.2) linux x64 (fedora 19)

代码的背景信息:我正在做的是找到从三角形顶部到底部的最高成本路线,这是从project_euler 18和67

The bug: I设置了一个名为pathA的变量,这是一个整数列表,加上从三角形中找到的新值的一个新int,例如,3,7,2附加8应该等于3,2,7,8,并且它等于!直到我设定了pathB。pathB的设置是正确的,但是突然之间,pathA与pathB的值相同。

tl;博士,当我设置另一个变量时,其中一个变量被覆盖。

我的代码如下:

代码语言:javascript
复制
package main

import (
    "fmt"
)

func extendPaths(triangle, prePaths [][]int) [][]int {
    nextLine := triangle[len(prePaths)]
    fmt.Println("#####PrePaths: ", prePaths)
    fmt.Println("#####nextLine: ", nextLine)

    postPaths := [][]int{{}}
    for i := 0; i < len(prePaths); i++ {
        route := prePaths[i]
        nextA := nextLine[i]
        nextB := nextLine[i+1]

        fmt.Println("Next A:", nextA, "Next B:", nextB, "\n")
        pathA := append(route, nextA)
        fmt.Println("pathA check#1:", pathA)
        pathB := append(route, nextB)
        fmt.Println("pathA check#2:", pathA, "\n")

        postPaths = append(postPaths, pathA)
        postPaths = append(postPaths, pathB)
    }
    postPaths = postPaths[1:]

    prePaths = [][]int{postPaths[0]}
    for i := 1; i < len(postPaths)-1; i += 2 {
        if getSum(postPaths[i]) > getSum(postPaths[i+1]) {
            prePaths = append(prePaths, postPaths[i])
        } else {
            prePaths = append(prePaths, postPaths[i+1])
        }
    }
    prePaths = append(prePaths, postPaths[len(postPaths)-1])
    return prePaths
}

func getSum(sumList []int) int {
    total := 0
    for i := 0; i < len(sumList); i++ {
        total += sumList[i]
    }
    return total
}

func getPaths(triangle [][]int) {
    prePaths := [][]int{{triangle[0][0]}}
    for i := 0; i < len(triangle)-1; i++ {
        prePaths = extendPaths(triangle, prePaths)
    }
}

func main() {
    triangle := [][]int{{3}, {7, 4}, {2, 4, 6}, {8, 5, 9, 3}}
    getPaths(triangle)
}

这给出了终端中的输出,如下所示:

代码语言:javascript
复制
#####PrePaths:  [[3]]
#####nextLine:  [7 4]
Next A: 7 Next B: 4

pathA check#1: [3 7]
pathA check#2: [3 7]

#####PrePaths:  [[3 7] [3 4]]
#####nextLine:  [2 4 6]
Next A: 2 Next B: 4

pathA check#1: [3 7 2]
pathA check#2: [3 7 2]

Next A: 4 Next B: 6

pathA check#1: [3 4 4]
pathA check#2: [3 4 4]

#####PrePaths:  [[3 7 2] [3 7 4] [3 4 6]]
#####nextLine:  [8 5 9 3]
Next A: 8 Next B: 5

pathA check#1: [3 7 2 8]
pathA check#2: [3 7 2 5]

Next A: 5 Next B: 9

pathA check#1: [3 7 4 5]
pathA check#2: [3 7 4 9]

Next A: 9 Next B: 3

pathA check#1: [3 4 6 9]
pathA check#2: [3 4 6 3]

在这里您可以看到,在我设置pathA的最后4次中,它最初是正确设置的,但随后被pathB覆盖。

有人对此有任何想法吗?

编辑:

正如下面的评论所指出的,所需要的是制作新的切片并从原件复制数据。这是使用来自稍微修改过的http://blog.golang.org/go-slices-usage-and-internals的代码完成的:

代码语言:javascript
复制
func AppendInt(slice []int, data ...int) []int {
    m := len(slice)
    n := m + len(data)
    if n > cap(slice) {
        newSlice := make([]int, (n+1)*2)
        copy(newSlice, slice)
        slice = newSlice
    }
    slice = slice[0:n]
    copy(slice[m:n], data)
    return slice
}

我还修改了另一边的代码,在那里我创建了片pathA和pathB。这一情况改为:

代码语言:javascript
复制
for i := 0; i < len(prePaths); i++ {

    nextA := nextLine[i]
    nextB := nextLine[i+1]

    pathA := AppendInt(prePaths[i], nextA)
    pathB := AppendInt(prePaths[i], nextB)

    postPaths = append(postPaths, pathA)
    postPaths = append(postPaths, pathB)
}

EDIT2:

现在已经很早了,我在第一次编辑时犯了一个错误,我没有完全理解你的解决方案,经过一些黑客攻击,我终于做到了:

此代码不工作(pathA被覆盖):

代码语言:javascript
复制
for i := 0; i < len(prePaths); i++ {

    nextA := nextLine[i]
    nextB := nextLine[i+1]

    pathA := append(prePaths[i], nextA)
    pathB := append(prePaths[i], nextB)

    postPaths = append(postPaths, pathA)
    postPaths = append(postPaths, pathB)
}

此代码也不工作(pathA被覆盖):

代码语言:javascript
复制
for i := 0; i < len(prePaths); i++ {

    newRoute := make([]int, len(prePaths[i]), (cap(prePaths[i])+1)*2)
    copy(newRoute, prePaths[i])

    nextA := nextLine[i]
    nextB := nextLine[i+1]

    pathA := append(newRoute, nextA)
    pathB := append(newRoute, nextB)

    postPaths = append(postPaths, pathA)
    postPaths = append(postPaths, pathB)
}

但是,如果我将上面的两个场景混合到下面的代码中,它就能正常工作(pathA不会被覆盖):

代码语言:javascript
复制
for i := 0; i < len(prePaths); i++ {

    newRoute := make([]int, len(prePaths[i]), (cap(prePaths[i])+1)*2)
    copy(newRoute, prePaths[i])

    nextA := nextLine[i]
    nextB := nextLine[i+1]

    pathA := append(newRoute, nextA)
    pathB := append(prePaths[i], nextB)

    postPaths = append(postPaths, pathA)
    postPaths = append(postPaths, pathB)
}

因此,我的解决方案是复制数组,让它们都使用不同的数组。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2013-11-29 02:45:32

一个切片基本上是一个由三件事组成的结构:

  1. 指向片中元素数组的指针。
  2. 数组的长度(“容量”)
  3. 实际存储在数组中的元素数(“长度”)

运行以下代码时:

代码语言:javascript
复制
append(x, element)

它做了以下工作:

  1. 检查扩展片是否会超过基础数组的容量。如果是这样,则分配一个更大的元素,并将现有元素复制到新数组中,并更新容量。
  2. 将新元素(或多个元素)写入数组的末尾,并更新长度。
  3. 把新的切片还回去。

在您的代码中,您有以下内容:

代码语言:javascript
复制
pathA := append(route, nextA)
pathB := append(route, nextB)

现在这里有两种可能性:

  1. len(route) == cap(route),并将分配一个新的支持数组,其中pathApathB具有独立的值。
  2. len(route) < cap(route),因此pathApathB最终共享了相同的支持数组。数组中的最后一个元素将是nextB,因为该操作是第二个运行的。

在循环的前几次迭代中,第一种情况似乎是正确的,在此之后,您进入了第二种情况。您可以通过手动为您的路径之一创建一个副本来避免这种情况(用make()分配一个片,然后使用copy()复制旧数据)。

票数 6
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/20277305

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档