是否可以动态设置json.Unmarshal的输出?

时间:2018-10-24 13:16:33

标签: json go reflection

我有以下Go代码:

/LTCG

我正在尝试传递一些JSON,以及一个表示JSON应该映射到的类型的字符串。我正在尝试使用反射将两者再次融合在一起,并通过方法名称将其传递给方法。

我有点喜欢它,但是,当我使用指针un CR LF时,它似乎再次失去了对其分配类型的引用,并且默认返回到var typeRegistry = make(map[string]reflect.Type) func init() { typeRegistry["User"] = reflect.TypeOf(User{}) } func makeInstance(name string) interface{} { v := reflect.New(typeRegistry[name]).Elem() return v.Interface() } func Invoke(any interface{}, name string, body []byte, signature Signature) { args := signature.Args data := makeInstance(signature.Args[0]) json.Unmarshal(body, &data) inputs := make([]reflect.Value, len(args)) for i, _ := range signature.Args { log.Println(reflect.TypeOf(data)) log.Println(reflect.ValueOf(data)) inputs[i] = reflect.ValueOf(data) } reflect.ValueOf(any).MethodByName(name).Call(inputs) } ,这是不匹配的我正在调用的方法。在这种情况下,期望类型为json.Unmarshal。如果我从map[string]interface{}中删除指针,则类型正确匹配,但是显然不再为main.User设置数据。

我知道我正在破坏Go的类型系统,并且可能以一种不建议的方式使用该语言,但是我想我正在尝试做一些学术性而非有用的事情。

1 个答案:

答案 0 :(得分:1)

您必须传递一个指向json.Unmarshal()的指针,否则它不能更改(指向的)数据,只能更改其副本。这是在您传递data时发生的事情:由于它不能更改值(User中包装的类型interface{}的非指针值),因此它可以创建一个新值进军它将选择最合适的选项(但不会像您经历的那样User,而是map[string]interface{})。

是的,您必须传递一个指向它的指针,但是&data并不是您想要的。 &data将是类型为*interface{}的接口的指针,因为makeInstance()返回的值为interface{}类型的值,因此data将具有该推断的类型。

解决方案是更改makeInstance()以返回可以包装在interface{}值中的指针,没关系。然后,您可以简单地将data传递给json.Unmarshal(),因为data接口值将保留类型*User的值。

也是这样:

func makeInstance(name string) interface{} {
    v := reflect.New(typeRegistry[name]) // Don't call Elem() here
    return v.Interface()
}

Invoke()中:

data := makeInstance(signature.Args[0])
json.Unmarshal(body, data)

查看几个小时前发布的相关问题:

Store information/reference about structure

您可以在此处查看有效的演示:Go Playground