结构体切片与指向结构体的指针切片的区别

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

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:

https://play.golang.org/p/YE-cokyEHu

huangapple
  • 本文由 发表于 2017年8月3日 02:08:42
  • 转载请务必保留本文链接:https://go.coder-hub.com/45468089.html
匿名

发表评论

匿名网友

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

确定