golang append to a slice inside struct

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

golang append to a slice inside struct

问题

我正在尝试理解如何在Go中操作数据结构以及它对指针的处理方式(是通过复制还是引用)。

你的代码在Go Playground上,链接在这里:https://play.golang.org/p/j_06RS5Xcz

我创建了一个包含切片的结构体映射,其中结构体内部还有其他东西的切片。

代码如下:

type Item struct {
    Name        string
    Description string
}

type Entity struct {
    Base   Item
    Others []Item
}

var database map[int][]Entity

func main() {
    database = make(map[int][]Entity)
    database[1] = []Entity{}

    e1 := Entity{}
    e1.Base = Item{"A", "aaa"}
    e1.Others = []Item{}

    database[1] = append(database[1], e1)

    // 后续,我想向实体添加其他项
    e1.Others = append(e1.Others, Item{"B", "bbb"})

    // 其他项字段为空
    fmt.Println(database)
}

// 输出:map[1:[{{A aaa} []}]]

我想在程序的后续部分追加其他项。看起来我必须使用指针来解决这个问题,但我不知道该如何做。

我的Entity结构体应该像这样吗?

type Entity struct {
    Base   Item
    Others *[]Item
}

如果是这样,我应该如何追加项呢?

*e1.Others = append(*e1.Others, Item{"B", "bbb"})

如果还有其他问题的话……我还不清楚在执行database[1] = append(database[1], e1)之前是否必须先执行database[1] = []Entity{},或者在这种情况下是否可以直接追加。我尝试了在e1.Others = []Item{}上进行相同的操作,但它没有产生相同的追加效果(我知道这是我的误解,而不是Go的问题)。

提前感谢你的帮助 golang append to a slice inside struct

英文:

I'm trying to understand how to manipulate data structures in Go, and its approach to pointers (with copies or references).

my code is on Go Playground, here: https://play.golang.org/p/j_06RS5Xcz

I made up a map of slices of a struct that also has a slice of other thing inside.

here:

type Item struct {
	Name        string
	Description string
}

type Entity struct {
	Base   Item
	Others []Item
}

var database map[int][]Entity

func main() {
	database = make(map[int][]Entity)
	database[1] = []Entity{}

	e1 := Entity{}
	e1.Base = Item{"A", "aaa"}
	e1.Others = []Item{}

	database[1] = append(database[1], e1)

	// later, I want to add other items to my entity
	e1.Others = append(e1.Others, Item{"B", "bbb"})

	// other items field is empty
	fmt.Println(database)
}

// prints: map[1:[{{A aaa} []}]]

I want to append the Others items later in my program. it seems that I must use pointers to solve this, but I don't know how.

should my Entity be like this?

type Entity struct {
	Base   Item
	Others *[]Item
}

and if so, how should I append items to it? like this?

*e1.Others = append(*e1.Others, Item{"B", "bbb"})

.

.

.

if there is room for another question... it is also not clear to me if I 'must' do: database[1] = []Entity{} before database[1] = append(database[1], e1) or I could just append in this case. I tried the same on e1.Others = []Item{} but it didn't produced the same effect to append (I know that this is my misunderstanding, not a Go's fault).

thanks in advance golang append to a slice inside struct

答案1

得分: 2

在你当前的代码中,你有两个类型为 Entity 的对象。一个名为 e1,另一个名为 database[1]。由于它们是 struct,所以这两个对象是完全独立的。因此,当你改变其中一个对象时,不会影响另一个对象。(小例外:对 Items 字段的某些更改将被共享,但不是全部。)

如果你想先将实体添加到地图中,然后再修改它,你应该使用指针的地图,即 map[int][]*Entity。然后,你应该创建一个指向实体的指针,而不是 Entity{},使用 e1 := &Entity{},然后程序将正常工作。对 e1.Others 的更改也会影响到 database[1].Others,因为这两个变量现在指向同一个对象。

但是 print 语句会有所不同。它不会打印结构体,而只会打印指针值。为了解决这个问题,可以添加一个 String 方法:

func (e *Entity) String() string { return fmt.Sprint(*e) }

请参考 https://play.golang.org/p/edU7E5Gnjw,我还删除了不必要的空切片。向 nil 切片追加元素是完全可以的。

如果想进一步了解,请参考 http://research.swtch.com/godata,它将回答你目前的问题。

英文:

In your current code, you have two objects of type Entity. One is named e1, the other is named database[1]. These two objects are completely independent, since they are structs. Therefore, when you change one of them, it will not affect the other. (Small exception: some changes to the Items field will be shared, but not all.)

If you want to first add the entity to the map and later modify it, you should use a map of pointers, map[int][]*Entity. Then, instead of Entity{}, you should create a pointer to an entity, with e1 := &Entity{}, and then the program will work. The changes to e1.Others will also affect database[1].Others, since these two variables now point to the same object.

But the print statement will be different. Instead of printing the struct, it will only print a pointer value. To fix this, add a String method:

func (e *Entity) String() string { return fmt.Sprint(*e) }

See https://play.golang.org/p/edU7E5Gnjw, where I also removed the needless empty slices. It is perfectly ok to append to a nil slice.

For further reading, I suggest http://research.swtch.com/godata, which will answer the questions that you currently have.

huangapple
  • 本文由 发表于 2016年8月18日 09:00:21
  • 转载请务必保留本文链接:https://go.coder-hub.com/39008410.html
匿名

发表评论

匿名网友

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

确定