Golang:将映射的键添加到切片的切片中

huangapple go评论62阅读模式
英文:

Golang: Appending keys from a map to a slice of slices

问题

我遇到了这段简单的 Golang 代码,对 Go 的行为感到惊讶。有人能解释一下这里发生了什么,并且如何正确编写下面的代码吗?

如你所见,我有一个 map,其中键是一个 int 数组。我添加了一些值,然后遍历该 map,将每个键转换为一个 slice,并将每个键附加到类型为 [][]int 的对象中。

func test() {
    myMap := make(map[[3]int]bool)
    myMap[[3]int{1, 2, 3}] = true
    myMap[[3]int{0, 5, 4}] = true
    myMap[[3]int{9, 7, 1}] = true
    myMap[[3]int{0, 2, 8}] = true
    array := [][]int{}

    for val := range myMap {
        array = append(array, val[:])
    }
    fmt.Println(array)
}

我原本期望最后一行打印 [[1,2,3], [0,5,4], [9,7,1], [0,2,8]],然而,令我惊讶的是它打印出了 [[0 2 8] [0 2 8] [0 2 8] [0 2 8]],或者 [[9 7 1] [9 7 1] [9 7 1] [9 7 1]],或者其他只包含一个键多次的变体。

我的 Go 版本是 1.16.5

英文:

I ran into this simple Golang code and was surprised by Go's behavior here. Can someone explain what is going on here, and how to write the below code correctly?

As you can see, I have a map, where the key is an array of int. I add a couple of values and then I loop through the map, convert each key to a slice and append each key to an object of type [][]int.

func test() {
	myMap := make(map[[3]int]bool)
	myMap[[3]int{1, 2, 3}] = true
	myMap[[3]int{0, 5, 4}] = true
	myMap[[3]int{9, 7, 1}] = true
	myMap[[3]int{0, 2, 8}] = true
	array := [][]int{}

	for val := range myMap {
		array = append(array, val[:])
	}
	fmt.Println(array)
}

I was expecting the last line to print [[1,2,3], [0,5,4], [9,7,1], [0,2,8]], however, to my surprise it prints [[0 2 8] [0 2 8] [0 2 8] [0 2 8]], or [[9 7 1] [9 7 1] [9 7 1] [9 7 1]], or some other variation containing only one of the keys multiple times.

My go version is 1.16.5

答案1

得分: 4

在for循环中,循环变量在每次迭代时被覆盖。也就是说,val是一个数组,每次迭代时,val的内容都会被下一个映射项覆盖。由于你添加了切片(切片只是数组的视图),所有的切片都以val作为支持数组,并且它们都具有相同的内容,即最后一个迭代的元素。

要修复这个问题,需要复制数组:

    for val := range myMap {
        val := val
        array = append(array, val[:])
    }
英文:

In a for-loop, the loop variables are overwriten at every iteration. That is, the val is an array, and for each iteration, the contents of val are overwritten with the next item in the map. Since you added slices (which are simply views over an array), all the slices have val as the backing array, and they all have the same contents, namely, whatever the last element iterated.

To fix, copy the array:

    for val := range myMap {
        val:=val
        array = append(array, val[:])
    }

答案2

得分: 3

你每次都在追加循环迭代变量,该变量在每次迭代时更新。你需要追加一个局部作用域的副本:

for val := range myMap {
    v := val
    array = append(array, v[:])
}
英文:

You're appending the loop iterator variable each time, which is updated each iteration. You need to append a locally-scoped copy instead:

for val := range myMap {
    v := val
    array = append(array, v[:])
}

答案3

得分: 1

根据Adrian的建议,使用以下简单程序重新创建你的代码:

package main

import (
	"fmt"
)

func main() {
	test()
}

func test() {
	myMap := make(map[[3]int]bool)
	myMap[[3]int{1, 2, 3}] = true
	myMap[[3]int{0, 5, 4}] = true
	myMap[[3]int{9, 7, 1}] = true
	myMap[[3]int{0, 2, 8}] = true
	array := [][]int{}

	for val := range myMap {
		key := val
		array = append(array, key[:])
	}

	fmt.Println(array)
}

输出结果:

[[1 2 3] [0 5 4] [9 7 1] [0 2 8]]
英文:

Based on suggestion of Adrian, recreating your code with a simple program as follows:

package main

import (
	"fmt"
)

func main() {
	test()
}
func test() {
	myMap := make(map[[3]int]bool)
	myMap[[3]int{1, 2, 3}] = true
	myMap[[3]int{0, 5, 4}] = true
	myMap[[3]int{9, 7, 1}] = true
	myMap[[3]int{0, 2, 8}] = true
	array := [][]int{}

	for val := range myMap {
		key := val
		array = append(array, key[:])

	}

	fmt.Println(array)
}

Output:

[[1 2 3] [0 5 4] [9 7 1] [0 2 8]]

huangapple
  • 本文由 发表于 2021年7月13日 00:50:59
  • 转载请务必保留本文链接:https://go.coder-hub.com/68351157.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定