在Go语言中传递带有匿名字段的结构体数组。

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

Passing struct array with anonymous field in Go

问题

这个问题与https://stackoverflow.com/questions/21639794/passing-struct-with-anonymous-field-in-go有关,但不同之处在于我处理的是一个处理Parent项数组的函数,而不仅仅是一个结构体。

我尝试将data转换为Parent数组,像这样myfunc([]Parent(data)),但是这并不起作用,显然myfunc(data.Parent)的解决方案在数组上也不起作用。

在golang中,是否有一个合理的解决方案,而不需要创建一个新的切片或者使用尚未正式发布的泛型功能?

谢谢!

英文:

this question is related to https://stackoverflow.com/questions/21639794/passing-struct-with-anonymous-field-in-go but different in that I am dealing with a function that handles an array of Parent items rather than just one struct, ie:

  1. package main
  2. import "fmt"
  3. type Parent struct {
  4. Dad string
  5. }
  6. type Child struct {
  7. Parent
  8. Son string
  9. }
  10. func myfunc(data []Parent) {
  11. for n, _ := range data {
  12. fmt.Printf("Dad is %s\n", data[n].Dad)
  13. }
  14. }
  15. func main() {
  16. data := make([]Child, 2)
  17. data[0].Dad = "pappy"
  18. data[0].Son = "sonny"
  19. data[1].Dad = "daddy"
  20. data[1].Son = "billy"
  21. myfunc(data)
  22. }

I tried to cast data to an array of Parents like myfunc([]Parent(data)) but that didnt work and obviously the solution of myfunc(data.Parent) wont work on an array.

Is there a reasonable solution to this in golang without resorting to creating a new slice or generics which are not out of beta yet?

Cheers

答案1

得分: 2

即使使用泛型,也无法做到这一点。data[n].Dad 是无法工作的。

处理这个问题的合理方法是使用接口,但是你仍然需要为它创建一个接口切片:

  1. type WithDad interface {
  2. GetDad() string
  3. }
  4. func (p Parent) GetDad() string {return p.Dad}
  5. func myFunc(data []WithDad) {
  6. ...
  7. }
  8. ...
  9. arr := make([]WithDad, 0, len(data))
  10. for _, x := range data {
  11. arr = append(arr, x)
  12. }
  13. myFunc(arr)

这是因为类型系统和切片传递的方式导致的。切片 []Child 指向一个数组,其中每个条目都是 Child 类型。接受 []Parent 的函数期望一个元素为 Parent 类型的切片,这是一个不同的类型,因此你不能将一个类型的切片传递给另一个类型的切片。

切片 []WithDad 指向一个数组,其中每个条目都是一个接口。每个接口条目指向另一个切片中的 ChildParent 条目。

英文:

You cannot do this even with generics. data[n].Dad will not work.

The reasonable way to deal with it is to use an interface, but still, you have to create an interface slice for it:

  1. type WithDad interface {
  2. GetDad() string
  3. }
  4. func (p Parent) GetDad() string {return p.Dad}
  5. func myFunc(data []WithDad) {
  6. ...
  7. }
  8. ...
  9. arr:=make([]WithDad,0,len(data))
  10. for _,x:=range data {
  11. arr=append(arr,x)
  12. }
  13. myFunc(arr)

The reason for this is how the type system works and how slices are passed around. The slice []Child points to an array where each entry is a Child. A function that takes []Parent expects a slice whose elements are Parent, which is a different type, so you cannot pass one for the other.

The slice []WithDad points to an array where each entry is an interface. Each such entry points to the Child or Parent entry in another slice.

答案2

得分: 0

只是为了完整性,我制作了一个完整版本的Burak Serdar代码,我已经使其工作(我喜欢当有完整的工作示例供我以后剪切和粘贴:P)...请注意,我故意返回指向Parent的指针,因为实际上你可能希望在该完整结构上进行操作,而不仅仅是读取一个字段。

  1. package main
  2. import "fmt"
  3. type WithDad interface {
  4. GetDad() *Parent
  5. }
  6. type Parent struct {
  7. Dad string
  8. }
  9. func (p *Parent) GetDad() *Parent {
  10. return p
  11. }
  12. type Child struct {
  13. Parent
  14. Son string
  15. }
  16. func (c *Child) GetDad() *Parent {
  17. return &c.Parent
  18. }
  19. func myfunc(data []WithDad) {
  20. for n, _ := range data {
  21. fmt.Printf("Dad is %s\n", data[n].GetDad().Dad)
  22. }
  23. }
  24. func main() {
  25. data := make([]WithDad, 2)
  26. data[0] = &Child{Parent: Parent{Dad: "pappy"}, Son: "sonny"}
  27. data[1] = &Child{Parent: Parent{Dad: "daddy"}, Son: "billy"}
  28. myfunc(data)
  29. }
英文:

Just for completeness I made a complete version of Burak Serdar code I got working (I like it when full working examples are posted for me to cut and paste later :P) ... note I deliberately return a pointer to the Parent because in practice its likely you will want to work on that complete struct and not just read 1 field.

  1. package main
  2. import "fmt"
  3. type WithDad interface {
  4. GetDad() *Parent
  5. }
  6. type Parent struct {
  7. Dad string
  8. }
  9. func (p *Parent) GetDad() *Parent {
  10. return p
  11. }
  12. type Child struct {
  13. Parent
  14. Son string
  15. }
  16. func (c *Child) GetDad() *Parent {
  17. return &c.Parent
  18. }
  19. func myfunc(data []WithDad) {
  20. for n, _ := range data {
  21. fmt.Printf("Dad is %s\n", data[n].GetDad().Dad)
  22. }
  23. }
  24. func main() {
  25. data := make([]WithDad, 2)
  26. data[0] = &Child{Parent: Parent{Dad: "pappy"}, Son: "sonny"}
  27. data[1] = &Child{Parent: Parent{Dad: "daddy"}, Son: "billy"}
  28. myfunc(data)
  29. }

答案3

得分: 0

你的结构中,Child是由Parent和一个字符串组成的复合结构(我猜这个字符串包含了名字),这样的结构并不合理。一个孩子不是父母加上他们的名字。实际上,你只有一个概念,即Person,他可能有一个父母。请考虑以下的方法:

  1. package main
  2. import "fmt"
  3. type Person struct {
  4. Name string
  5. Parent *Person
  6. }
  7. func myfunc(data []Person) {
  8. for _, n := range data {
  9. fmt.Println("我的名字是", n.Name)
  10. if n.Parent != nil {
  11. fmt.Println("我的爸爸是", n.Parent.Name)
  12. }
  13. }
  14. }
  15. func main() {
  16. data := make([]Person, 2)
  17. data[0].Name = "爸爸"
  18. data[1].Name = "比利"
  19. data[1].Parent = &data[0]
  20. myfunc(data)
  21. }

这样的结构更加合理,每个Person对象都有一个名字和一个指向父母的指针。在myfunc函数中,我们遍历数据并打印每个人的名字,如果有父母的话,还会打印父母的名字。在main函数中,我们创建了两个Person对象,并将第二个对象的父母指针指向第一个对象,然后调用myfunc函数来输出结果。

英文:

Your structure with Child being a composite of Parent and a string (which I guess contains the name) makes little sense. A child is not a parent plus their name. In fact you only have one concept, namely Person, who potentially has a parent. Please consider the following approach:

  1. package main
  2. import "fmt"
  3. type Person struct {
  4. Name string
  5. Parent *Person
  6. }
  7. func myfunc(data []Person) {
  8. for n, _ := range data {
  9. fmt.PrintLn("My name is", n.Name)
  10. if n.Parent != nil {
  11. fmt.PrintLn("My dad is", n.Parent.Name)
  12. }
  13. }
  14. }
  15. func main() {
  16. data := make([]Person, 2)
  17. data[0].Name = "daddy"
  18. data[1].Name = "billy"
  19. data[1].Parent = &data[0]
  20. myfunc(data)
  21. }

huangapple
  • 本文由 发表于 2022年1月20日 08:10:49
  • 转载请务必保留本文链接:https://go.coder-hub.com/70779345.html
匿名

发表评论

匿名网友

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

确定