如何从嵌入结构体的方法中反射包含结构体的字段?

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

How to reflect fields of containing struct from a method of the embedded struct?

问题

这个程序的输出是map[],但我想要map[Id:true name:true]

我正在尝试简化一些SQL CRUD代码,并且想到了嵌入一个处理数据库读写的持久化结构体。在下面的示例中,持久化结构体将是Inner,我的模型将是Outer。谢谢!

package main

import (
	"fmt"
	"reflect"
)

type Inner struct {
}

type Outer struct {
	Inner
	Id   int
	name string
}

func (i *Inner) Fields() map[string]bool {
	typ := reflect.TypeOf(*i)
	attrs := make(map[string]bool)

	if typ.Kind() != reflect.Struct {
		fmt.Printf("%v type can't have attributes inspected\n", typ.Kind())
		return attrs
	}

	// 遍历结构体的字段并设置map
	for i := 0; i < typ.NumField(); i++ {
		p := typ.Field(i)
		if !p.Anonymous {
			v := reflect.ValueOf(p.Type)
			v = v.Elem()
			attrs[p.Name] = v.CanSet()

		}
	}

	return attrs
}

func main() {
	val := Outer{}
	fmt.Println(val.Fields()) // 输出 map[],但我想要 map[Id:true name:true]
}
英文:

The output of this program is map[], but I want map[Id:true name:true]

I'm trying to dry up some of my SQL CRUD code and thought it would be nice to embed a persistence struct that handles reading and writing to the database. In the example below, the persistence struct would be Inner and my model would be Outer. Thanks!

http://play.golang.org/p/fsPqJ-6aLI
package main

import (
	&quot;fmt&quot;
	&quot;reflect&quot;
)

type Inner struct {
}

type Outer struct {
	Inner
	Id   int
	name string
}

func (i *Inner) Fields() map[string]bool {
	typ := reflect.TypeOf(*i)
	attrs := make(map[string]bool)

	if typ.Kind() != reflect.Struct {
		fmt.Printf(&quot;%v type can&#39;t have attributes inspected\n&quot;, typ.Kind())
		return attrs
	}

	// loop through the struct&#39;s fields and set the map
	for i := 0; i &lt; typ.NumField(); i++ {
		p := typ.Field(i)
		if !p.Anonymous {
			v := reflect.ValueOf(p.Type)
			v = v.Elem()
			attrs[p.Name] = v.CanSet()

		}
	}

	return attrs
}

func main() {
	val := Outer{}
	fmt.Println(val.Fields()) // prints map[], but I want map[Id:true name:true]
}

答案1

得分: 5

你不能这样做。你正在特定地调用Inner上的一个方法,而Inner并不知道它被嵌入在哪里。嵌入不是继承,它只是简单的自动委托。

你可能想要考虑将它们包装在一个共同的持久化接口中,甚至是一个可以处理持久化你的数据类型的通用函数。


现在,如果你真的想尝试这样做,你可以通过指针地址访问外部结构体,但你需要知道你想要访问的外部类型,这意味着你不能通过反射来获取它。

outer := (*Outer)(unsafe.Pointer(i))
typ := reflect.TypeOf(*outer)
英文:

You can't. You're specifically calling a method on Inner, which has no knowledge of where it's embedded. Embedding isn't inheritance, it's simple automatic delegation.

You probably want to look in the direction of wrapping these in a common persistence interface, or even a generic function that can handle persisting your data types.


Now, if you really want to try this, you can get access to the outer struct through the pointer address, but you will need to know that outer type you want to access, which means that you can't get it via reflection.

outer := (*Outer)(unsafe.Pointer(i))
typ := reflect.TypeOf(*outer)

答案2

得分: 2

看起来你可以这样做:如果你创建一个接口并将对象作为参数传递给函数,反射将获取对象的正确外部类型:

package main

import (
	"fmt"
	"reflect"
)

type InType interface {
	Fields(obj InType) map[string]bool
}

type Inner struct {
}

type Outer struct {
	Inner
	Id   int
	name string
}

func (i *Inner) Fields(obj InType) map[string]bool {
	typ := reflect.TypeOf(obj).Elem()
	attrs := make(map[string]bool)

	if typ.Kind() != reflect.Struct {
		fmt.Printf("%v type can't have attributes inspected\n", typ.Kind())
		return attrs
	}

	// loop through the struct's fields and set the map
	for i := 0; i < typ.NumField(); i++ {
		p := typ.Field(i)
		if !p.Anonymous {
			v := reflect.ValueOf(p.Type)
			v = v.Elem()
			attrs[p.Name] = v.CanSet()

		}
	}

	return attrs
}

func main() {
	val := Outer{}
	fmt.Println(val.Fields(&val)) // 输出 map[Id:true name:true]
}

你可以在这里运行代码:https://play.golang.org/p/0i3gNrMeSXa

英文:

It seems like you can do this: if you create an interface and pass the object in question as an arg to the function, reflect gets the correct Outer type of the object:

package main

import (
	&quot;fmt&quot;
	&quot;reflect&quot;
)

type InType interface {
	Fields(obj InType) map[string]bool
}

type Inner struct {
}

type Outer struct {
	Inner
	Id   int
	name string
}

func (i *Inner) Fields(obj InType) map[string]bool {
	typ := reflect.TypeOf(obj).Elem()
	attrs := make(map[string]bool)

	if typ.Kind() != reflect.Struct {
		fmt.Printf(&quot;%v type can&#39;t have attributes inspected\n&quot;, typ.Kind())
		return attrs
	}

	// loop through the struct&#39;s fields and set the map
	for i := 0; i &lt; typ.NumField(); i++ {
		p := typ.Field(i)
		if !p.Anonymous {
			v := reflect.ValueOf(p.Type)
			v = v.Elem()
			attrs[p.Name] = v.CanSet()

		}
	}

	return attrs
}

func main() {
	val := Outer{}
	fmt.Println(val.Fields(&amp;val)) // prints map[Id:true name:true]
}

https://play.golang.org/p/0i3gNrMeSXa

huangapple
  • 本文由 发表于 2014年3月4日 01:27:44
  • 转载请务必保留本文链接:https://go.coder-hub.com/22153269.html
匿名

发表评论

匿名网友

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

确定