2015-07-13 16 views
2

我正在使用golang。這裏是我的代碼:Golang:在片上使用append時出現問題

func main() { 
    quanPailie([]int{1, 2}) 
} 

func quanPailie(nums []int) [][]int { 
    COUNT := len(nums) 

    //only one item 
    if COUNT == 1 { 
     return [][]int{nums} 
    } 

    insertItem(quanPailie(nums[:COUNT-1]), nums[COUNT-1]) 
    return [][]int{} 
} 

func insertItem(res [][]int, insertNum int) { 
    fmt.Println("insertItem,res:", res, "insertNum", insertNum) //insertItem,res: [[1]] insertNum 2 

    for _, v := range res { 
     for i := 0; i < len(v); i++ { 
      fmt.Println("===before,v:", v) 
      c := append(v[:i], append([]int{insertNum}, v[i:]...)...) 
      fmt.Println("===after,v:", v) 

      fmt.Println("ccc", c) 

     } 
    } 
} 

什麼讓我很困惑的輸出:

===before,v: [1] 
===after,v: [2] 

爲什麼v變化的價值?希望可以有人幫幫我。非常感謝。

轉到操場:https://play.golang.org/p/wITYsGpX7U

編輯:
感謝icza的很大的幫助,我想我已經明白了這個問題。
而且,下面是顯示此問題的簡單代碼。

func test1() { 
    nums := []int{1, 2, 3} 
    _ = append(nums[:2], 4) 
    fmt.Println("test1:", nums) 

    //nums changes because the cap is big enought, the original array is modified. 

} 

func test2() { 
    nums := []int{1, 2, 3} 
    c := append(nums[:2], []int{4, 5, 6}...) 
    fmt.Println("test2:", nums) 
    fmt.Println("cc:", c) 

    //nums dont't change because the cap isn't big enought. 
    //a new array is allocated while the nums still points to the old array. 
    //Of course, the return value of append points to the new array. 
} 

轉到操場:https://play.golang.org/p/jBNFsCqUn3

+0

追加行爲:http://criticalindirection.com/2016/02/17/slice-with-a-pinch-of-salt/ – user31986

回答

4

這是有問題的代碼:

fmt.Println("===before,v:", v) 
c := append(v[:i], append([]int{insertNum}, v[i:]...)...) 
fmt.Println("===after,v:", v) 

你問爲什麼2個Println()語句之間v變化。

因爲使用內建append()功能,從它的文檔引用:

追加內置函數追加元素切片的末端。 如果它具有足夠的容量,目的地將被重新組合以適應新的元素。如果沒有,將分配一個新的底層數組。追加返回更新的切片。

所以,如果你追加到片有足夠的空間(容量),以容納要附加的元素,沒有新的切片將被分配,而不是目的片段將被重新切片(這將使用相同的底層數組)和追加將發生在那。

讓我們來看看容量:

fmt.Println("===before,v:", v, cap(v)) 
c := append(v[:i], append([]int{insertNum}, v[i:]...)...) 
fmt.Println("===after,v:", v, cap(v)) 

輸出:

===before,v: [1] 2 
===after,v: [2] 2 

v片有2能力。當for循環開始時,i=0,v[:i]v[:0],它是一個空片(但容量爲2),因此追加1或2個元素將不會分配新的數組/片,它將「就地」完成。這個「in place」是v的第0個元素,因爲v[:i]v[0:i]的簡寫。因此,元素將從v[0]開始附加到共享的基礎數組中,因此由v[0]表示的元素將發生更改。

請注意,對切片進行切片會產生與原始切片共享其底層支持陣列的切片(不會製作元素的副本)。

如果你想避免這種情況,使用或分配一個新的切片,copy原創內容並追加新的切片,如:在圍棋

src := []int{1, 2} 
c := make([]int, len(src)) 
copy(c, src) 
// Append something: 
c = append(c, 3, 4) 

fmt.Println(src) // [1 2] - src doesn't change 
fmt.Println(c) // [1 2 3 4] 
+0

感謝@icza。我想我已經理解了這個問題。 – hanswim

相關問題