将值附加到切片时,值与原始值不同

时间:2018-06-14 14:24:19

标签: go

考虑这段代码:

package main

import (
    "fmt"
)

func main() {
    fmt.Println(Part(11))
}

func Part(n int) string {
    enumResult := [][]int{}
    enum(n, n, []int{}, &enumResult)
    fmt.Println(enumResult)
    fmt.Println(40, enumResult[40])
    return ""
}

var abc int = 0

func enum(n int, top int, pre []int, result *[][]int) {
    var i int
    if n > top {
        i = top
    } else {
        i = n
    }
    for ; i > 0; i-- {
        tempResult := append(pre, i)
        if n-i == 0 {
            /*  if tempResult[0] == 3 && tempResult[1] == 3 && tempResult[2] == 3 && tempResult[3] == 2 {
                tempResult = append(tempResult, 12345)
            }*/
            fmt.Println(abc, tempResult)
            abc++
            *result = append(*result, tempResult)
        } else {
            enum(n-i, i, tempResult, result)
        }
    }
}

当我运行此代码时

我将'[3,3,3,2]'附加到'enumResult'

但是,如果我检查'enumResult'的值,则会出现'[3,3,3,1]'

它的索引是40 => enumResult [40] (其他值是正确的)

我不知道为什么会这样 你能解释一下为什么吗?

1 个答案:

答案 0 :(得分:0)

问题确实归因于append

append有两件事。首先,append不一定要复制记忆。由于spec指定:

  

如果s的容量不足以容纳附加值,   append分配一个适合的新的,足够大的底层数组   现有的切片元素和附加值。 ,否则下,   追加重新使用基础数组。

如果您不清楚,这可能会导致意外行为。一个游乐场示例:https://play.golang.org/p/7A3JR-5IX8o

第二部分是,当append复制内存时,它会增加切片的容量。但是,它不会仅仅增加1.游乐场示例:https://play.golang.org/p/STr9jMqORUz

切片的append增长多少未记录,并被视为实施细节。但是直到Go 1.10,它遵循这条规则:

  

切片增长一倍,直到大小1024,之后它们会增长   每次25%。

请注意,启用竞赛检测器时,可能会发生变化。增长切片的代码位于$GOROOT/src/runtime/slice.go函数中的growslice

现在回到这个问题。现在应该很清楚,由于之前append的切片增长,您的代码从具有足够容量的相同切片中执行append。要解决此问题,请创建一个新切片并复制内存。

tempResult := make([]int,len(pre)+1)
copy(tempResult,pre)
tempResult[len(pre)] = i