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

y4ekin9u  于 2023-03-21  发布在  Go
关注(0)|答案(2)|浏览(78)

我很想知道为什么,请给予我一点提示。
我想在res中添加一个数组,res是一个二维切片,所以我需要先进行转换,当我将数组转换为切片时,出现了一个bug。

// 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循环
一个二个一个一个
现在结果是正确的,但是为什么呢?k[:][]int{k[0],k[1],k[2]}有什么不同?

iszxjhcz

iszxjhcz1#

将循环更改为

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

你最初的循环声明了一个[3]int类型的变量k,它在内存中有一个特定的位置,循环的每次迭代,Mapmm中的一个不同的键都会被复制到那个变量中,到目前为止,一切都很好。
当你用k[:]把它转换成一个切片时,它会创建一个切片头,指向数组k。这里出错了--下一次循环时,k的值会被覆盖。循环中创建的所有切片都指向内存中相同位置的相同后备数组k
通过首先将k的值复制到一个在循环 * 内部 * 声明的变量,您可以为每个切片提供自己的支持数组,从而避免了这个问题。

dauxcl2d

dauxcl2d2#

The Go Programming Language Specification
For语句
带range子句的For语句
迭代变量可以由“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]]

相关问题