在Golang中,`array[:]`和`[]slice{array[0],array[1],...}`有什么区别?

问题描述 投票:0回答:2

我很想知道为什么,请给我一点提示。

我想在

res
中附加一个数组,
res
是一个二维切片。所以我需要先转换。 当我将数组转换为切片时,出现错误。

// I need a map to remove duplicates
mm := map[[3]int]bool{}
mm[[3]int{-1, -1, 2}] = true
mm[[3]int{-1, -1, 2}] = true
mm[[3]int{-1, 0, 1}] = true

var res [][]int
for k, _ := range mm {
    res = append(res, k[:])
}
fmt.Printf("the res is %v\n", res)
the res is [[-1 0 1] [-1 0 1]]

但结果不是我想要的

然后我试探性地修改了一下for循环

for k, _ := range mm {
    //res = append(res, k[:])
    res = append(res, []int{k[0], k[1], k[2]})
}
the res is [[-1 0 1] [-1 -1 2]]

现在结果是对的,但是为什么呢?

k[:]
[]int{k[0],k[1],k[2]}
有什么区别?

arrays algorithm go slice
2个回答
0
投票

将循环更改为

for k, _ := range mm {
    j := k
    res = append(res, j[:])
}

您的原始循环声明了一个类型为

k
的变量
[3]int
,它在内存中有一个特定的位置。循环的每次迭代,都会将来自 map
mm
的不同键复制到该变量。到目前为止,一切都很好。

当您使用

k[:]
将其转换为切片时,它会创建一个切片标头,points 到数组
k
。这里出了问题——循环的下一次迭代,
k
的值被覆盖。在循环中创建的所有切片都指向内存中相同位置的相同后备数组
k

通过首先将

k
的值复制到在循环中内部 声明的变量,您为每个切片提供了自己的后备数组,从而避免了这个问题。


0
投票

Go 编程语言规范

陈述

对于带有范围子句的语句

迭代变量可以使用短变量声明(:=)的形式由“range”子句声明。在这种情况下,它们的类型被设置为各自迭代值的类型,它们的范围是“for”语句的块;它们在每次迭代中都会重复使用。

添加

k := k
语句将重复使用的迭代变量
k
与每次迭代的局部变量
k
隐藏在一起。

包主

import "fmt"

func main() {
    mm := map[[3]int]bool{}
    mm[[3]int{-1, -1, 2}] = true
    mm[[3]int{-1, -1, 2}] = true
    mm[[3]int{-1, 0, 1}] = true
    fmt.Println(mm)

    var res [][]int
    for k, _ := range mm {
        k := k
        res = append(res, k[:])
    }
    fmt.Println(res)
}

https://go.dev/play/p/4BdXzdThxXd

map[[-1 -1 2]:true [-1 0 1]:true]
[[-1 -1 2] [-1 0 1]]
© www.soinside.com 2019 - 2024. All rights reserved.