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

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

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:

package main

import "fmt"

type Parent struct {
	Dad string
}

type Child struct {
	Parent
	Son string
}

func myfunc(data []Parent) {
	for n, _ := range data {
		fmt.Printf("Dad is %s\n", data[n].Dad)
	}
}

func main() {
	data := make([]Child, 2)
	data[0].Dad = "pappy"
	data[0].Son = "sonny"
	data[1].Dad = "daddy"
	data[1].Son = "billy"
	myfunc(data)
}

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 是无法工作的。

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

type WithDad interface {
   GetDad() string
}

func (p Parent) GetDad() string {return p.Dad}

func myFunc(data []WithDad) {
   ...
}

...
arr := make([]WithDad, 0, len(data))
for _, x := range data {
  arr = append(arr, x)
}
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:

type WithDad interface {
   GetDad() string
}

func (p Parent) GetDad() string {return p.Dad}

func myFunc(data []WithDad) {
   ...
}

...
arr:=make([]WithDad,0,len(data))
for _,x:=range data {
  arr=append(arr,x)
}
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的指针,因为实际上你可能希望在该完整结构上进行操作,而不仅仅是读取一个字段。

package main

import "fmt"

type WithDad interface {
	GetDad() *Parent
}

type Parent struct {
	Dad string
}

func (p *Parent) GetDad() *Parent {
	return p
}

type Child struct {
	Parent
	Son string
}

func (c *Child) GetDad() *Parent {
	return &c.Parent
}

func myfunc(data []WithDad) {
	for n, _ := range data {
		fmt.Printf("Dad is %s\n", data[n].GetDad().Dad)
	}
}

func main() {
	data := make([]WithDad, 2)
	data[0] = &Child{Parent: Parent{Dad: "pappy"}, Son: "sonny"}
	data[1] = &Child{Parent: Parent{Dad: "daddy"}, Son: "billy"}
	myfunc(data)
}
英文:

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.

package main

import "fmt"

type WithDad interface {
	GetDad() *Parent
}

type Parent struct {
	Dad string
}

func (p *Parent) GetDad() *Parent {
	return p
}

type Child struct {
	Parent
	Son string
}

func (c *Child) GetDad() *Parent {
	return &c.Parent
}

func myfunc(data []WithDad) {
	for n, _ := range data {
		fmt.Printf("Dad is %s\n", data[n].GetDad().Dad)
	}
}

func main() {
	data := make([]WithDad, 2)
	data[0] = &Child{Parent: Parent{Dad: "pappy"}, Son: "sonny"}
	data[1] = &Child{Parent: Parent{Dad: "daddy"}, Son: "billy"}
	myfunc(data)
}

答案3

得分: 0

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

package main

import "fmt"

type Person struct {
   Name   string
   Parent *Person
}

func myfunc(data []Person) {
    for _, n := range data {
        fmt.Println("我的名字是", n.Name)
        if n.Parent != nil {
            fmt.Println("我的爸爸是", n.Parent.Name)
        }
    }
}

func main() {
    data := make([]Person, 2)
    data[0].Name = "爸爸"
    data[1].Name = "比利"
    data[1].Parent = &data[0]
    myfunc(data)
}

这样的结构更加合理,每个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:

package main

import "fmt"

type Person struct {
   Name string
   Parent *Person
}

func myfunc(data []Person) {
    for n, _ := range data {
        fmt.PrintLn("My name is", n.Name)
        if n.Parent != nil {
            fmt.PrintLn("My dad is", n.Parent.Name)
        }
    }
}

func main() {
    data := make([]Person, 2)
    data[0].Name = "daddy"
    data[1].Name = "billy"
    data[1].Parent = &data[0]
    myfunc(data)
}

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:

确定