[英]golang - reflection on embedded structs
Given a struct like so:给定一个像这样的结构:
type B struct {
X string
Y string
}
type D struct {
B
Z string
}
I want to reflect on D and get to the fields X, Y, Z.我想反思 D 并进入 X、Y、Z 领域。
Intuitively, before attempting the solution, I was assuming I would be able to traverse the struct D and get all fields using reflection (X, Y, Z) and won't have to deal with B.直观地说,在尝试解决方案之前,我假设我能够遍历结构 D 并使用反射(X、Y、Z)获取所有字段,而不必处理 B。
But as you can see, I only see the embedded struct B using reflection and not its fields.但是正如您所看到的,我只看到使用反射的嵌入式结构 B 而不是它的字段。
http://play.golang.org/p/qZQD5GdTA8 http://play.golang.org/p/qZQD5GdTA8
Is there a way I can make B fully transparent when reflecting on D?有没有办法让 B 在反射到 D 时完全透明?
Why do I want this?我为什么要这个?
Imaging a common struct (B in the example here), that is used in multiple other structs by using embedding.对一个公共结构(此处示例中的 B)进行成像,该结构通过使用嵌入在多个其他结构中使用。 Using reflection, the attempt is to copy D into another similar struct in a different package.
使用反射,尝试将 D 复制到不同包中的另一个类似结构中。 The destination struct for copying will have all attributes flatly laid out (no embedding there).
用于复制的目标结构将具有平面布局的所有属性(没有嵌入)。 So there is a mismatch from the source to the destination (embedding vs no embedding) but all the attributes flatly laid out are the same.
因此,从源到目标存在不匹配(嵌入与无嵌入),但所有平铺的属性都是相同的。 I don't want to create custom solutions for each struct.
我不想为每个结构创建自定义解决方案。
The 'transparency' you expected is just syntactic sugar and has nothing to do with the data representation.您期望的“透明度”只是语法糖,与数据表示无关。 If you want to have a function that flattens your data structure, you would have to write it by yourself.
如果您想拥有一个扁平化数据结构的函数,则必须自己编写。
For example ( On play ):例如(在玩):
func DeepFields(iface interface{}) []reflect.Value {
fields := make([]reflect.Value, 0)
ifv := reflect.ValueOf(iface)
ift := reflect.TypeOf(iface)
for i := 0; i < ift.NumField(); i++ {
v := ifv.Field(i)
switch v.Kind() {
case reflect.Struct:
fields = append(fields, DeepFields(v.Interface())...)
default:
fields = append(fields, v)
}
}
return fields
}
Use the following code to collect all promoted field names as keys in map m
:使用以下代码收集所有提升的字段名称作为映射
m
键:
func collectFieldNames(t reflect.Type, m map[string]struct{}) {
// Return if not struct or pointer to struct.
if t.Kind() == reflect.Ptr {
t = t.Elem()
}
if t.Kind() != reflect.Struct {
return
}
// Iterate through fields collecting names in map.
for i := 0; i < t.NumField(); i++ {
sf := t.Field(i)
m[sf.Name] = struct{}{}
// Recurse into anonymous fields.
if sf.Anonymous {
collectFieldNames(sf.Type, m)
}
}
}
Use it like this:像这样使用它:
m := make(map[string]struct{})
collectFieldNames(reflect.TypeOf((*D)(nil)), m)
for name := range m {
fmt.Println(name)
}
Run it on the playground .在操场上运行它。
This program prints X, Y an Z as requested in the question, but also B because B is also a field name.该程序按照问题的要求打印 X、Y 和 Z,但也打印 B,因为 B 也是字段名称。
This function in this answer can be improved:此答案中的此功能可以改进:
The typeField
function in encoding/json/encode.go handles both of these issues. encoding/json/encode.go 中的
typeField
函数处理这两个问题。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.