本文介绍了变量被覆盖(bug?)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这里有点奇怪。我的问题是,像我一样,人们运行代码的结果是否相同?如果你这样做,是我的代码(我通常是一个python程序员)或者golang中的错误吗?


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



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



错误:我设置了一个名为pathA的变量,这是一个整数列表,加上一个新的int,用于从三角形
找到的新值3,7,2追加8应该等于3,2,7,8
,它的确如此! ...直到我设置路径B. pathB被正确设置,但突然pathA与pathB的值相同。


$ b tl; dr 当我设置另一个变量时, p>

我的代码如下:

 包主

import(
fmt


func extendPaths(triangle,prePaths [] [] int)[] [] int {
nextLine:= (##### nextLine:,nextLine)

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

fmt.Println(下一个A:,nextA,Next B:,nextB,\\\

pathA:= append(route,nextA)
fmt.Println(pathA check#1:, pathA)
pathB:= append(route,nextB)
fmt.Println(pathA check#2:,pathA,\\\


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

prePaths = [] [] int {postPaths [0]}
for i:= 1;我< 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])$ ​​b $ b return prePaths
}

func getSum (sumList [] int)int {
total:= 0
for i:= 0;我< LEN(sumList); i ++ {
total + = sumList [i]
}
返回总数
}

func getPaths(triangle [] [] int){
prePaths:= [] [] int {{triangle [0] [0]}}
for i:= 0;我< LEN(三角形)-1; i ++ {
prePaths = extendPaths(triangle,prePaths)
}
}

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


 <$> 
$ b

这给出了终端中的输出: c $ c> ##### PrePaths:[[3]]
##### nextLine:[7 4]
下一个A:7下一个B:4

pathA检查#1:[3 7]
pathA检查#2:[3 7]

##### PrePaths:[[3 7] [3 4]]
##### nextLine:[2 4 6]
下一个A:2下一个B:4

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

下一个A:4下一个B:6

pathA支票#1:[3 4 4]
pathA支票#2 :[3 4 4]

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

pathA支票#1:[3 7 2 8]
pathA支票#2:[3 7 2 5 ]

下一个A:5下一个B:9

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

下一个A:9下一个B: 3

pathA支票#1:[3 4 6 9]
pathA支票#2:[3 4 6 3]

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



有没有人对此有任何想法?

编辑:

正如下面的评论所指出的那样,需要从原件制作新的切片和复制数据。这是通过 http://blog.golang.org/go-slices

  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;我< LEN(prePaths); i ++ {
$ b $ 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被覆盖):

  for i:= 0;我< LEN(prePaths); i ++ {
$ b $ 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;我< 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;我< 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)
}

所以,我的解决方案是制作数组的副本,并让它们使用不同的数组。 p>

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


  1. 指向切片中元素数组的指针
  2. 该数组的长度(容量)

  3. 实际存储在数组中的元素的数量(长度)

运行以下代码时:

 附加(x,元素)

它遵循以下ng:


  1. 检查扩展切片是否会超出底层数组的容量。如果是这样,请分配一个较大的元素,并将现有元素复制到新数组中,并更新容量。
  2. 将新元素(或元素)写入数组的末尾并更新。
  3. 返回新的分片。



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

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

    现在有两种可能性:


    1. len(route)== cap(route),并且将分配一个新的后备数组,其中 pathA pathB 具有独立的值。
    2. len(route) cap(route),所以 pathA pathB 最终共享相同的支持数组。数组中的最后一个元素将是 nextB ,因为该操作是以秒为单位运行的。



    看起来,第一种情况对于你的循环的第一次迭代是正确的,在这之后,你遇到了第二种情况。你可以通过手动为你的路径创建一个副本来避免这种情况(使用 make()分配一个片段,然后使用 copy() code>复制旧数据)。


    So bit of a weird one here. My question is, do people get the same results from running my code as I do? And if you do, is it a fault of my code (I'm a python programmer usually), or a bug in golang?

    System info: Go version (1.1.2) linux x64 (fedora 19)

    Background info on the code: What I'm doing is finding the highest cost route from the top of a triangle to the bottom, this is from project_euler 18 and 67

    The bug: I set a variable called pathA, this is an integer list, plus a new int for the new value found from the trianglee.g. 3, 7, 2 append 8 should equal 3, 2, 7, 8and, it does! ... until I set pathB. pathB gets set correctly however suddenly pathA is the same value as pathB.

    tl;dr one variable is being overwritten when I set another

    My code is as follows:

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

    This gives the output in my terminal shown below:

    #####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]
    

    Here you can see that for the last 4 times that I set pathA, it is initially set correctly, but then gets overwritten by pathB.

    Does anyone have any thoughts on this?

    EDIT:

    As pointed out by the comments below, what was needed was to make new slices and copy data from the originals. This was done using code from http://blog.golang.org/go-slices-usage-and-internals modified slightly:

    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
    }
    

    I also changed the code on the other side, where I created the slices pathA and pathB. This changed to:

    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:

    It's quite early in the morning here, and I flat out made a mistake in my first edit, I did not fully understand your solution, after a bit of hacking I got there in the end:

    This code does not work (pathA gets overwritten):

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

    This code also does not work (pathA gets overwritten):

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

    However, if I mix the 2 scenarios above into the code below, it works fine (pathA does not get overwritten):

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

    So, my solution was to make a copy of the array, and have them both use different ones.

    解决方案

    A slice is basically a structure consisting of 3 things:

    1. A pointer to an array of the elements in the slice
    2. The length of that array (the "capacity")
    3. The number of elements actually stored in the array (the "length")

    When you run the following code:

    append(x, element)
    

    It does the following:

    1. Check if extending the slice will exceed the capacity of the underlying array. If so, allocate a larger one and copy the existing elements to the new array, and update the capacity.
    2. Write the new element (or elements) to the end of the array and update the length.
    3. Return the new slice.

    In your code, you have the following:

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

    Now there are two possibilities here:

    1. len(route) == cap(route), and a new backing array will be allocated, with pathA and pathB having independent values.
    2. len(route) < cap(route), so pathA and pathB end up sharing the same backing array. The last element in the array will be nextB, since that operation was run second.

    It seems that the first case is true for the first few iterations of your loop, after which you hit the second case. You could avoid this by manually making a copy for one of your paths (allocate a slice with make(), and then use copy() to copy the old data).

    这篇关于变量被覆盖(bug?)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-13 02:34