英文:
Go Unmarshal reflect.Type got map[string]interface{}
问题
我想将JSON字符串转换为某个结构体,用作函数参数。
我使用反射来获取参数类型,这个方法很好用,
但是如果我使用json.Unmarshal,我总是得到map[string]interface{}类型的结果。
这是一个简单的运行示例,文件名为json_test.go:
package testJson
import (
"reflect"
"encoding/json"
"testing"
"log"
)
type LoginForm struct {
Name string
}
func Login(login LoginForm) {
}
func TestRun(t *testing.T) {
_func := Login
f := reflect.ValueOf(_func)
funcType := f.Type()
paramType := funcType.In(0)
log.Print(paramType.Name())
v := reflect.New(paramType).Elem().Interface()
jsonstr := `{"Name":"123"}`
log.Print(jsonstr)
log.Print(reflect.TypeOf(v).Name())
log.Print("%+v", v)
err := json.Unmarshal([]byte(jsonstr), &v)
if err != nil {
panic(err)
}
log.Print(reflect.TypeOf(v).Name())
log.Print(v)
var in []reflect.Value
in = make([]reflect.Value, funcType.NumIn())
in[0] = reflect.ValueOf(v)
f.Call(in)
}
谢谢你的帮助!
英文:
I want to convert json string to some struct ,use as func param
I use reflect to get Param Type,this work fine ,
but if I use json.Unmarshal I always get map[string]interface{}
this is a mini Run sample,File name is json_test.go
<!-- begin snippet: js hide: false console: true babel: false -->
package testJson
import (
"reflect"
"encoding/json"
"testing"
"log"
)
type LoginForm struct {
Name string
}
func Login(login LoginForm) {
}
func TestRun(t *testing.T) {
_func := Login
f := reflect.ValueOf(_func)
funcType := f.Type()
paramType := funcType.In(0)
log.Print(paramType.Name())
v := reflect.New(paramType).Elem().Interface()
jsonstr := `{"Name":"123"}`
log.Print(jsonstr)
log.Print(reflect.TypeOf(v).Name())
log.Print("%+v", v)
err := json.Unmarshal([]byte(jsonstr), &v)
if err != nil {
panic(err)
}
log.Print(reflect.TypeOf(v).Name())
log.Print( v)
var in []reflect.Value
in = make([]reflect.Value, funcType.NumIn())
in[0] = reflect.ValueOf(v)
f.Call(in)
}
<!-- end snippet -->
Thanks for your help!
答案1
得分: 2
不要使用reflect.New来创建指针类型,因为其结果是指向指针的指针,而应该使用reflect.New来创建指针类型的Elem。
将这段代码:
v := reflect.New(paramType).Elem().Interface()
改为:
v := reflect.New(paramType.Elem()).Interface()
此时,v已经是指向LoginForm的指针,因此在传递给Unmarshal时不需要使用&获取其地址。
此外,你得到map[string]interface{}的原因是因为Interface()方法的返回类型是interface{},所以v的底层类型可以是任何类型,但其“最顶层”的类型是interface{}。因此,使用&v将得到*interface{},而不是预期的*LoginForm。在文档中可以找到,尝试将JSON对象解组为interface{}将导致类型为map[string]interface{}的值。
英文:
Don't reflect.New a pointer type because the result of that is a pointer to the pointer, instead reflect.New the Elem of the pointer type.
Change this:
v := reflect.New(paramType).Elem().Interface()
To this:
v := reflect.New(paramType.Elem()).Interface()
At this point v is already a pointer to LoginForm so you don't need to get its address with & when passing to Unmarshal.
https://play.golang.org/p/JM4fRXb7fo
Also the reason you got map[string]interface{} is because the return type of the Interface() method is unsurprisingly enough interface{}, so while v's underlying type could be anything its "topmost" type is interface{}. So then, doing &v will get you *interface{} as opposed to the inteded *LoginForm. And in the docs you can find that trying to unmarshal a JSON object into an interface{} will result in a value of type map[string]interface{}.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。


评论