英文:
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]]
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论