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


评论