golang reflect 无法识别来自地图成员的标签

我想用反射提取结构的映射成员的标签,而我发现如果从 MapIndex 检索成员的值,它的类型将被识别为“*接口{}”因此所有类型信息都丢失,没有提到反射可以提取细节信息。


package main


import (

    "fmt"

    "reflect"

)


type Student struct {

    Sname string `MyTag:"student-name"`

}


type Teacher struct {

    Name     string             `MyTag:"teacher-name"`

    Students map[string]Student `MyTag:"teacher-students"`

}


var sam = Teacher{

    Name: "Sam",

    Students: map[string]Student{

        "Sen": {

            Sname: "Sen",

        },

    },

}


func traversalTag(obj interface{}) {

    theType := reflect.TypeOf(obj)

    fmt.Printf("Traversal tag with obj: type %v, value %v\n", theType.String(), obj)


    elem := reflect.TypeOf(obj).Elem()

    for i := 0; i < elem.NumField(); i++ {

        fmt.Printf("Tag name %s, value %s\n", elem.Field(i).Name, elem.Field(i).Tag)

    }

}


func tryMapWithType(students map[string]Student) {

    for key, theValue := range students {

        fmt.Printf("Key: %v, Value: %v, value pointer %p\n", key, theValue, &theValue)

        traversalTag(&theValue)

    }

}


func tryMapWithReflect(obj interface{}) {

    reflectMap := reflect.ValueOf(obj)

    for _, key := range reflectMap.MapKeys() {

        theValue := reflectMap.MapIndex(key).Interface()

        fmt.Printf("Key: %v, Value: %v, value pointer %p\n", key, theValue, &theValue)

        traversalTag(&theValue) // Will have error

    }

}


func main() {

    tryMapWithType(sam.Students)

    tryMapWithReflect(sam.Students)

}

运行后出现以下错误:


Starting: C:\Users\Mento\go\bin\dlv.exe dap --check-go-version=false --listen=127.0.0.1:50308 from d:\Coding\Golang\demo

DAP server listening at: 127.0.0.1:50308

Key: Sen, Value: {Sen}, value pointer 0xc000044230

Traversal tag with obj: type *main.Student, value &{Sen}

Tag name Sname, value MyTag:"student-name"

Key: Sen, Value: {Sen}, value pointer 0xc0000442c0

Traversal tag with obj: type *interface {}, value 0xc0000442c0

panic: reflect: NumField of non-struct type interface {}


谁能提示如何使用原始类型信息获取地图成员的指针?


饮歌长啸
浏览 110回答 1
1回答

HUX布斯

如您所知,使用&theValue解析为类型*interface{}。该类型*interface{}不同于*Student您传递给traversalTagfrom的类型tryMapWithType。如果要传递*Student给traversalTagfrom tryMapWithReflect,则需要使用反射创建该指针值。简单的原生 Go 地址运算符&是不够的。当您拥有reflect.Value可寻址的 a 时,您需要做的就是调用该.Addr()方法以获取指向可寻址值的指针,但是映射元素不可寻址,因此reflectMap.MapIndex(key)不可寻址。所以,不幸的是,你无法reflectMap.MapIndex(key).Addr().Interface()获得*Student.因此,您唯一的选择是使用反射来创建该*Student类型的新值,将指向的值设置为映射中的值,然后返回该类型的值.Interface()。func tryMapWithReflect(obj interface{}) {&nbsp; &nbsp; reflectMap := reflect.ValueOf(obj)&nbsp; &nbsp; for _, key := range reflectMap.MapKeys() {&nbsp; &nbsp; &nbsp; &nbsp; theValue := reflectMap.MapIndex(key).Interface()&nbsp; &nbsp; &nbsp; &nbsp; // allocate a new value of type *Student&nbsp; &nbsp; &nbsp; &nbsp; newValue := reflect.New(reflectMap.MapIndex(key).Type())&nbsp; &nbsp; &nbsp; &nbsp; // use Elem do dereference *Stunded&nbsp; &nbsp; &nbsp; &nbsp; // and then use Set to set the Student to the content of theValue&nbsp; &nbsp; &nbsp; &nbsp; newValue.Elem().Set(reflect.ValueOf(theValue))&nbsp; &nbsp; &nbsp; &nbsp; fmt.Printf("Key: %v, Value: %v, value pointer %p\n", key, newValue.Elem().Interface(), newValue.Interface())&nbsp; &nbsp; &nbsp; &nbsp; // return the newValue *Student&nbsp; &nbsp; &nbsp; &nbsp; traversalTag(newValue.Interface())&nbsp; &nbsp; }}https://go.dev/play/p/pNL2wjsOW5y.Elem()或者,只需从 the 中删除 thetraversalTag然后就不必将指针传递给它。func traversalTag(obj interface{}) {&nbsp; &nbsp; theType := reflect.TypeOf(obj)&nbsp; &nbsp; fmt.Printf("Traversal tag with obj: type %v, value %v\n", theType.String(), obj)&nbsp; &nbsp; elem := reflect.TypeOf(obj)&nbsp; &nbsp; for i := 0; i < elem.NumField(); i++ {&nbsp; &nbsp; &nbsp; &nbsp; fmt.Printf("Tag name %s, value %s\n", elem.Field(i).Name, elem.Field(i).Tag)&nbsp; &nbsp; }}https://go.dev/play/p/EwJ5e0uc2pd
打开App,查看更多内容
随时随地看视频慕课网APP