我有以下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的类型系统,并且可能以一种不建议的方式使用该语言,但是我想我正在尝试做一些学术性而非有用的事情。
答案 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。