go - 将值附加到 slice 时,值与原始值不同

标签 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] (其他值正确)

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

最佳答案

确实是append的问题。

关于append有两件事。首先,append 不一定复制内存。作为spec指定:

If the capacity of s is not large enough to fit the additional values, append allocates a new, sufficiently large underlying array that fits both the existing slice elements and the additional values. Otherwise, append re-uses the underlying array.

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

第二部分是,当append 复制内存时,它会增加 slice 的容量。然而,它不会只增加 1。 Playground 示例:https://play.golang.org/p/STr9jMqORUz

slice 增长多少 append 是未记录的,被认为是实现细节。但是直到 Go 1.10,它遵循这个规则:

Go slices grow by doubling until size 1024, after which they grow by 25% each time.

请注意,启用竞争检测器时,这可能会改变。增长 slice 的代码位于$GOROOT/src/runtime/slice.go中的growslice函数。

现在回到问题。现在应该很清楚,由于之前 append 的 slice 增长,您的代码确实从具有足够容量的同一 slice append 。为了解决它,制作一个新的 slice 并复制内存。

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

关于go - 将值附加到 slice 时,值与原始值不同,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50859784/

相关文章:

go - "package main"在 main.go 文件夹中标记为红色的错误

go - 使用 gRPC 状态包中的 WithDetails() 传递自定义原型(prototype)消息

docker - 基于 Golang 的 docker 镜像构建有效,但不能基于 Scratch 的镜像

ssl - 带有 client.crt 和 client.key 的 https 请求

go - 如何测试二进制字符串是否有效的UTF8?

戈朗 : file extracted from tar throws permissions error

go - 在 Go 语言中如何像 c/c++ 中的 freopen 一样从文件中逐步获取输入

go - 为什么golang.org/x/sys软件包鼓励使用要替换的syscall软件包?

string - 拆分字符串并将子字符串转换为 Go 中的整数

amazon-web-services - AWS RDS 代理连接