通用函数使用可嵌入的结构体。

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

Generic function using embeddable structs

问题

我正在尝试编写一个函数,该函数将处理某种类型的对象,并调用作为参数之一传递的特定方法。由于Go语言中没有继承或泛型,我正在使用嵌入(embedding)。(我不能使用接口,因为接口只能定义方法,而我还需要结构体字段。)

我对Go语言还不熟悉,所以肯定做错了一些事情。以下是我代码的简化版本:

package main

import "fmt"
import "reflect"

type Animal struct {
    Type string
}

type Dog struct {
    Animal
}

type Cat struct {
    Animal
}

func (d *Dog) SayWoof() {
    fmt.Println("WOOF")
}

func (c *Cat) SayMeouw() {
    fmt.Println("MEOUW")
}

func CallMethod(animal interface{}, baseAnimal *Animal, methodName string) {
    fmt.Println("Animal type: ", baseAnimal.Type)

    method := reflect.ValueOf(animal).MethodByName(methodName)
    if !method.IsValid() {
        return
    }

    method.Call([]reflect.Value{})
}

func main() {
    dog := &Dog{}
    dog.Type = "Dog" // for some reason dog := &Dog{Type: "Dog"} doesn't compile

    cat := &Cat{}
    cat.Type = "Cat"

    CallMethod(dog, &dog.Animal, "SayWoof")
    CallMethod(cat, &cat.Animal, "SayMeouw")
}

输出结果:

Animal type:  Dog
WOOF
Animal type:  Cat
MEOUW

这段代码可以工作,但是我基本上需要两次传递对象:首先是一个接口来动态调用方法,然后是嵌入的("父")对象来访问其字段。

我更希望有这样的函数定义:

func CallMethod(animal Animal, methodName string)

但是,如果将Dog对象强制转换为Animal对象,像这样:

CallMethod(dog.Animal, "SayWoof")

显然不起作用,因为Animal中没有定义"SayWoof"方法。

所以问题是:有没有办法只传递一个子对象给函数,并访问其所有的反射数据?

谢谢!

英文:

I'm trying to write a function that will process a certain type of objects and call a certain method passed as one of the args. Since there's no inheritance or generics, I'm using embedding. (I can't use interfaces as you can only define methods in them, and I need struct fields as well).

I'm new at Go, so I'm definitely doing something wrong. Here's a simplified version of my code:

http://play.golang.org/p/r0mtDXtmWc

package main

import "fmt"
import "reflect"

type Animal struct {
	Type string
}

type Dog struct {
	Animal
}

type Cat struct {
	Animal
}

func (d *Dog) SayWoof() {
	fmt.Println("WOOF")
}

func (c *Cat) SayMeouw() {
	fmt.Println("MEOUW")
}

func CallMethod(animal interface{}, baseAnimal *Animal, methodName string) {
	fmt.Println("Animal type: ", baseAnimal.Type)

	method := reflect.ValueOf(animal).MethodByName(methodName)
	if !method.IsValid() {
		return
	}

	method.Call([]reflect.Value{})
}

func main() {
	dog := &Dog{}
	dog.Type = "Dog" // for some reason dog := &Dog{Type: "Dog"} doesn't compile

	cat := &Cat{}
	cat.Type = "Cat"

	CallMethod(dog, &dog.Animal, "SayWoof")
	CallMethod(cat, &cat.Animal, "SayMeouw")
}

output:

Animal type:  Dog
WOOF
Animal type:  Cat
MEOUW

This code works, but I basically need to pass an object twice: first an interface to call a method dynamically and then the embedded ("parent") object to get access to its fields.

I would much rather have something like

func CallMethod(animal Animal, methodName string)

but then if cast a Dog object to an Animal like this:

CallMethod(dog.Animal, "SayWoof")

it obviously won't work as there's no "SayWoof" method defined in Animal.

So the question is: is there a way to pass a child object to a function once and have access to all its reflection data?

Thanks

答案1

得分: 1

包 main

import "fmt"

type Animal interface {
Speak()
}

type Dog struct {
}

type Cat struct {
}

func (d *Dog) Speak() {
fmt.Println("Woof")
}

func (c *Cat) Speak() {
fmt.Println("Meow")
}

func Speaketh(a Animal) {
a.Speak()
}

func main() {
dog := Dog{}
cat := Cat{}
Speaketh(&dog)
Speaketh(&cat)
}

你对泛型语言到底有什么期望来解决你的问题呢?这是一个诚实的问题。对于你想要调用"SayMeow"和"SayWoof"这两个不同的函数名,没有任何类型不可知的数据结构能够帮助你神奇地调用正确的函数。

英文:
package main

import "fmt"

type Animal interface {
    Speak()
}

type Dog struct {
}

type Cat struct {
}

func (d *Dog) Speak() {
    fmt.Println("Woof")
}

func (c *Cat) Speak() {
    fmt.Println("Meow")
}

func Speaketh(a Animal) {
    a.Speak()
}

func main() {
    dog := Dog{}
    cat := Cat{}
    Speaketh(&dog)
    Speaketh(&cat)
}

How exactly would you expect a language with generics to solve your problem anyway? That's an honest question. With different function names you want to call "SayMeow" and "SayWoof", no type agnostic data structure is going to help you magically call the right thing.

huangapple
  • 本文由 发表于 2014年2月25日 16:56:18
  • 转载请务必保留本文链接:https://go.coder-hub.com/22009081.html
匿名

发表评论

匿名网友

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

确定