在Golang中,`array[:]`和`[]slice{array[0],array[1],…}`有什么不同?

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

in Golang, what's the different between `array[:]` and `[]slice{array[0],array[1],...}` ?

问题

我很乐意告诉你原因,请给我一点提示。

我想将一个数组追加到res中,而res是一个二维切片。所以我需要先进行转换。
当我将一个数组转换为切片时,出现了一个错误。

// 我需要一个映射来去除重复项
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]}之间有什么区别?

英文:

I'd love to know why, please give me a little hint.

I want to append an array into res, the res is a Two-dimensional slice. So I need convert first.
When I convert an array into a slice, there is a 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]]

But the result is not what I want.

then I tentatively modified the for loop a bit

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]]

now the result is right, but why?
What's the different between k[:] and []int{k[0],k[1],k[2]}?

答案1

得分: 2

将循环改为:

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

你原来的循环声明了一个类型为 [3]int 的变量 k,它在内存中有一个特定的位置。每次循环迭代,k 都会被赋予来自 mm 映射的不同键的值。到目前为止,一切都好。

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

通过首先将 k 的值复制到在循环内部声明的变量中,你为每个切片都提供了自己的后备数组,并避免了这个问题。

英文:

Change the loop to

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

Your original loop declares a variable k of type [3]int, which has a particular location in memory. Every iteration of the loop, a different key from map mm is copied to that variable. So far, so good.

When you convert it to a slice using k[:], it creates a slice header that points to the array k. It goes wrong here - the next iteration of the loop, the value of k gets overwritten. All slices created in the loop point to the same backing array k at the same location in memory.

By copying the value of k first to a variable that was declared inside the loop, you give each slice its own backing array, and you avoid the problem.

答案2

得分: 2

《Go编程语言规范》

对于带有范围子句的for语句

可以通过“range”子句使用短变量声明(:=)来声明迭代变量。在这种情况下,它们的类型被设置为相应迭代值的类型,并且它们的作用域是“for”语句的块;它们在每次迭代中被重用。

添加k := k语句会用本地变量k遮蔽被重用的迭代变量k,每次迭代都会创建一个新的本地变量k

package main

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)
}

输出结果:

map[[-1 -1 2]:true [-1 0 1]:true]
[[-1 -1 2] [-1 0 1]]

你可以在以下链接中查看代码的运行结果:https://go.dev/play/p/4BdXzdThxXd

英文:

> The Go Programming Language Specification
>
> For statements
>
> For statements with range clause
>
> The iteration variables may be declared by the "range" clause using a form of short variable declaration (:=). In this case their types are set to the types of the respective iteration values and their scope is the block of the "for" statement; they are re-used in each iteration.

Adding the k := k statement shadows the re-used iteration variable k with a local variable k for each iteration.

package main

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]]

huangapple
  • 本文由 发表于 2023年3月18日 12:45:06
  • 转载请务必保留本文链接:https://go.coder-hub.com/75773909.html
匿名

发表评论

匿名网友

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

确定