Go变量被覆盖(错误?)

 xwu9052591 发布于 2023-02-13 20:45

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

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

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

错误:我设置了一个名为pathA的变量,这是一个整数列表,并为从三角形中找到的新值添加了一个新的int值,例如3、7、2追加8应该等于3、2、7、8,而且确实如此!...直到设置pathB。pathB设置正确,但是突然pathA与pathB的值相同。

tl; dr当我设置另一个变量时,一个变量被覆盖

我的代码如下:

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)
}

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

#####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中的代码进行了稍微修改的:

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。更改为:

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)
}

编辑2:

这是一大早,在进行第一次编辑时,我全力以赴,但我不完全理解您的解决方案,经过一番黑客之后,我终于到达了那里:

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

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被覆盖):

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不会被覆盖):

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)
}

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

1 个回答
  • 切片基本上是由三部分组成的结构:

      指向切片中元素数组的指针

      该数组的长度(“容量”)

      实际存储在数组中的元素数(“长度”)

    当您运行以下代码时:

    append(x, element)
    

    它执行以下操作:

      检查扩展切片是否会超出基础数组的容量。如果是这样,请分配更大的一个并将现有元素复制到新阵列,然后更新容量。

      将一个或多个新元素写入数组的末尾并更新长度。

      返回新的切片。

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

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

    现在这里有两种可能性:

      len(route) == cap(route),然后将分配一个新的支持数组,pathApathB具有独立的值。

      len(route) < cap(route),所以pathApathB最终共享相同的背衬阵列。数组中的最后一个元素将是nextB,因为该操作第二次运行。

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

    2023-02-13 20:51 回答
撰写答案
今天,你开发时遇到什么问题呢?
立即提问
热门标签
PHP1.CN | 中国最专业的PHP中文社区 | PNG素材下载 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有