英文:
Slice of structs vs a slice of pointers to structs
问题
我不理解以下代码片段的行为。在创建一个匹配的结构体指针切片的过程中,代码总是打印原始数组的最后一个元素(实际上并不匹配)- 它打印出了12和12。然而,如果我将matches的类型从[]*Widget更改为[]Widget,那么它将打印出10和11。
为什么会这样呢?
package main
import (
"fmt"
)
func main() {
type Widget struct {
id int
attrs []string
}
widgets := []Widget{
Widget{
id: 10,
attrs: []string{"blah", "foo"},
},
Widget{
id: 11,
attrs: []string{"foo", "bar"},
},
Widget{
id: 12,
attrs: []string{"xyz"},
},
}
var matches []*Widget
for _, w := range widgets {
for _, a := range w.attrs {
if a == "foo" {
matches = append(matches, &w)
break
}
}
}
for _, m := range matches {
fmt.Println(m.id)
}
}
链接:代码
英文:
I don't understand the behavior of the following piece of code. In creating a list of matching structs as a slice of struct pointers, the code always prints the last element of original array (which actually wasn't a match)—it prints 12 and 12. However, if I change matches to be []Widget instead of []*Widget, then it will print 10 and 11.
Why is this?
package main
import (
"fmt"
)
func main() {
type Widget struct {
id int
attrs []string
}
widgets := []Widget{
Widget{
id: 10,
attrs: []string{"blah", "foo"},
},
Widget{
id: 11,
attrs: []string{"foo", "bar"},
},
Widget{
id: 12,
attrs: []string{"xyz"},
},
}
var matches []*Widget
for _, w := range widgets {
for _, a := range w.attrs {
if a == "foo" {
matches = append(matches, &w)
break
}
}
}
for _, m := range matches {
fmt.Println(m.id)
}
}
答案1
得分: 8
这是因为当你使用指针时,你将&w
添加到了数组中。
请注意,w
实际上是循环中使用的局部变量,所以这不是你想要添加到matches
数组中的地址。
(尽管变量w
的值在循环中发生了变化,但它的地址保持不变)
当循环结束时,w
最终会得到最后一个值,这就是为什么它会打印两次12
的原因。
你需要添加匹配元素的地址。
如果你这样做:
matches = append(matches, &widgets[i])
那么使用指针也能正常工作。
这是一个修改后的Go Playground链接,供你测试:
https://play.golang.org/p/YE-cokyEHu
英文:
That's because when you use the pointers you are adding &w
to the array.
Note that w
is actually the local variable used in the loop, so that's not the address you want to add to the matches
array.
(even though the value of the variable w
changes through the loop, its address stays the same)
When the loop ends, w
ends up with the last value so that's why it prints 12
two times.
You need to add the address of the element that matched instead.
If you do this:
matches = append(matches, &widgets[i])
Then it'd work fine with pointers as well.
Modified Go playground for you to test it:
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论