2013-11-29 218 views
4

這裏有一個奇怪的位。我的問題是,像我一樣,人們運行代碼的結果是否相同?如果你這樣做,這是我的代碼(我通常是一個Python程序員)的錯誤,或者是golang中的錯誤?變量被覆蓋(bug?)

系統信息:轉到版本(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相同的值。

TL;博士當我設置一個可變被覆蓋另一個

我的代碼如下:

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

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

它在這裏的早晨很早就和我平掉髮在我的第一個編輯錯誤,我沒有完全理解你的解決方案,後位黑客的我到底到了那裏:

此代碼不能正常工作(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) 
} 

但是,如果我混上面到下面的代碼中的2種情況,它工作正常(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) 
} 

所以,我的解決方案是製作陣列的副本,並讓它們都使用不同的陣列。

回答

4

切片是基本上由3個東西的結構:

  1. 的指針元件的陣列中的切片
  2. 該陣列(「容量」)的長度
  3. 的元件的數目實際存儲的陣列(「長度」)在

當運行以下代碼:

append(x, element) 

它執行以下操作:

  1. 檢查延伸的切片將超過底層陣列的容量。如果是這樣,請分配一個較大的元素並將現有元素複製到新陣列中,並更新容量。
  2. 將新元素(或元素)寫入數組的末尾並更新長度。
  3. 返回新切片。現在有兩種可能性在這裏

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

    1. len(route) == cap(route),和一個新的支持數組將被分配,以pathApathB

    在代碼中,你有以下具有獨立的價值。

  4. len(route) < cap(route),所以pathApathB最終共享相同的支持陣列。數組中的最後一個元素將是nextB,因爲該操作是第二次運行的。

看起來第一種情況在您的循環的前幾次迭代中是正確的,之後您會遇到第二種情況。您可以通過手動爲其中一個路徑創建副本(分配make()的分片,然後使用copy()複製舊數據)來避免此問題。

+0

+1,正要寫出:) – nemo

+0

非常感謝您對此的幫助。這解決了我所看到的問題。我已經更新了主帖,以反映所做的更改 – Gwynnie

+0

請注意,如果您始終想要創建新的分片,則最好分配所需的確切長度,而不是像編輯時那樣將容量加倍題。擁有'cap> len'真的只有在你用「追加」或類似方法逐漸增長的情況下才有用。 –