英文:
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
指向一个数组,其中每个条目都是一个接口。每个接口条目指向另一个切片中的 Child
或 Parent
条目。
英文:
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)
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论