如何从GO结构体中获取嵌入类型?

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

How to get embedded type from GO struct?

问题

我正在尝试从Go结构体中获取嵌入类型。下面是一个演示这一点的示例程序。有没有一种方法可以在不枚举每种可能的输入类型的情况下编写myfunc()函数?

package main

import (
	"fmt"
)

type ObjectMeta struct {
	Name      string
	Namespace string
}

type A struct {
	ObjectMeta
	X string
}

type B struct {
	ObjectMeta
	X string
}

func myfunc(v interface{}) ObjectMeta {
	switch u := v.(type) {
	case *A:
		return u.ObjectMeta
	case A:
		return u.ObjectMeta
	case *B:
		return u.ObjectMeta
	case B:
		return u.ObjectMeta
	}
	panic("No matching type")
}

func main() {
	fmt.Println(myfunc(&A{}))

	var v interface{} = &A{}
	fmt.Println(v.(*ObjectMeta))
}

ObjectMetaAB结构体存在于外部项目中,我无法对它们进行控制。

英文:

I am trying to get embedded type from Go structs. Below is an example program that demonstrates this. Is there a way to write myfunc() without enumerating every type that can come in as input?
https://play.golang.org/p/5wp14O660m

package main

import (
	"fmt"
)

type ObjectMeta struct {
	Name string
	Namespace string
}

type A struct {
	ObjectMeta
	X string
}

type B struct {
	ObjectMeta

	X string
}

func myfunc(v interface{}) ObjectMeta {
	switch u := v.(type) {
	case *A:
		return u.ObjectMeta
	case A:
		return u.ObjectMeta
	case *B:
		return u.ObjectMeta
	case B:
		return u.ObjectMeta
	}
	panic("No matching type")
}

func main() {
	fmt.Println(myfunc(&A{}))
	
	var v interface{} = &A{}
	fmt.Println(v.(*ObjectMeta))
}

ObjectMeta, A, B structs exist in external project. I have no control over them.

答案1

得分: 1

可以使用反射(reflection)来完成,通过迭代传入值的字段:

func myfunc(v interface{}) ObjectMeta {
    // 使用Elem()解引用指针
    ifv := reflect.ValueOf(v).Elem()
    ift := reflect.TypeOf(v).Elem()

    for i := 0; i < ift.NumField(); i++ {
        f := ift.Field(i)
        if f.Name == "ObjectMeta" {
            fv := ifv.Field(i)
            return fv.Interface().(ObjectMeta)
        }
    }
    panic("ObjectMeta未找到")
}

Playground: https://play.golang.org/p/CzMHJWhxYr

英文:

It can be done using reflection, iterating through the fields of the incoming value:

func myfunc(v interface{}) ObjectMeta {
    // Elem() to de-reference pointer
    ifv := reflect.ValueOf(v).Elem()
    ift := reflect.TypeOf(v).Elem()

    for i := 0; i &lt; ift.NumField(); i++ {
        f := ift.Field(i)
        if f.Name == &quot;ObjectMeta&quot; {
            fv := ifv.Field(i)
            return fv.Interface().(ObjectMeta)
        }
    }
    panic(&quot;ObjectMeta not found&quot;)
}

Playground: https://play.golang.org/p/CzMHJWhxYr

答案2

得分: 0

你可以定义一个接口来获取嵌入类型:

package main

import (
	"fmt"
)

type HasMeta interface {
	GetMeta() ObjectMeta
}

type ObjectMeta struct {
	Name      string
	Namespace string
}

func (o ObjectMeta) GetMeta() ObjectMeta {
	return o
}

type A struct {
	ObjectMeta
	X string
}

type B struct {
	ObjectMeta
	X string
}

func myfunc(o HasMeta) ObjectMeta {
	return o.GetMeta()
}

func main() {
	fmt.Println(myfunc(&A{}))
	fmt.Println(myfunc(A{}))
	fmt.Println(myfunc(&B{}))
	fmt.Println(myfunc(B{}))
}

点击此处查看代码运行示例。

英文:

You can define interface which will get you that embedded type:

package main

import (
	&quot;fmt&quot;
)

type HasMeta interface {
	GetMeta() ObjectMeta
}

type ObjectMeta struct {
	Name      string
	Namespace string
}

func (o ObjectMeta) GetMeta() ObjectMeta {
	return o
}

type A struct {
	ObjectMeta
	X string
}

type B struct {
	ObjectMeta
	X string
}

func myfunc(o HasMeta) ObjectMeta {
	return o.GetMeta()
}

func main() {
    fmt.Println(myfunc(&amp;A{}))
    fmt.Println(myfunc(A{}))
    fmt.Println(myfunc(&amp;B{}))
    fmt.Println(myfunc(B{}))
}

https://play.golang.org/p/CWa4k-kvvl

huangapple
  • 本文由 发表于 2017年9月14日 05:04:19
  • 转载请务必保留本文链接:https://go.coder-hub.com/46206828.html
匿名

发表评论

匿名网友

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

确定