去解析反射类型得到了map[string]interface{}。

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

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 (
	&quot;reflect&quot;
	&quot;encoding/json&quot;
	&quot;testing&quot;
	&quot;log&quot;
)

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 := `{&quot;Name&quot;:&quot;123&quot;}`
	log.Print(jsonstr)
	log.Print(reflect.TypeOf(v).Name())
	log.Print(&quot;%+v&quot;, v)
	err := json.Unmarshal([]byte(jsonstr), &amp;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 &amp; 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 &amp;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{}.

huangapple
  • 本文由 发表于 2017年9月8日 16:43:07
  • 转载请务必保留本文链接:https://go.coder-hub.com/46112282.html
匿名

发表评论

匿名网友

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

确定