英文:
Casting interface{} to calculated in runtime Type
问题
这是我需要的示例原理图:
func decode(data []byte, target interface{}) (interface{}, error) {
decoded := target.(reflect.TypeOf(target)) // 伪代码
err := json.Unmarshal(data, &decoded)
...
我在 Stack Overflow 上找到了几个类似的问题,但所有的解决方案都是使用 target.(type)
进行切换。这不是我寻找的最佳解决方案。
我还找到了使用反射的解决方案:
decoded := reflect.ValueOf(target).Convert(reflect.TypeOf(target))
// fmt.Printf("%T", decoded) == reflect.Value
但我不知道如何从 reflect.Value
中获取结构体,以便将其传递给 json.Unmarshal
函数。
这个 decode
函数将如何使用?
我有多个不同结构的请求。我可以确定我应该使用哪个结构来解码请求。我有一个请求类型和结构之间的映射,类似于 map[RequestMethod]interface{}
。
示意版本如下:
func hydrate(data []byte) (interface{}, error) {
var base baseResponse
if err := json.Unmarshal(data, &base); err != nil {
return nil, err
}
target, ok := methodsMap[Method(base.Method)]
if !ok {
return nil, errors.New("Trying to hydrate data with unknown method: " + base.Method)
}
decoded, err := decode(data, target) // 期望的目标类型。
// 添加:
如果我们将 `target` 传递给 `json.Unmarshal` 而不进行类型转换,我们将得到 `map`。示例:
```go
func decode(data []byte, target interface{}) (interface{}, error) {
err := json.Unmarshal(data, &target)
// fmt.Printf("%T", target) == map[string]interface{} 而不是结构体。
```
**解决方案**
感谢 [@icza](https://stackoverflow.com/users/1705598/icza),我们找到了解决方案:
```go
func hydrate(data []byte) (interface{}, error) {
var base baseResponse
if err := json.Unmarshal(data, &base); err != nil {
return nil, err
}
target, ok := methodsMap[Method(base.Method)]
if !ok {
return nil, errors.New("Trying to hydrate data with unknown method: " + base.Method)
}
// 克隆请求草稿结构。
decoded := reflect.New(reflect.ValueOf(target).Type()).Interface()
err := decode(data, decoded)
...
相关链接:
- https://stackoverflow.com/questions/38829941/golang-interface-type-misunderstanding/38830638#38830638
- https://stackoverflow.com/questions/37851500/how-to-copy-an-interface-value-in-go/37851764#37851764
英文:
Here is schematic example what I need:
func decode(data []byte, target interface{}) (interface{}, error) {
decoded := target.(reflect.TypeOf(target)) // pseudocode
err := json.Unmarshal(data, &decoded)
...
I found several similar questions on SO, but all solutions are about switch by target.(type)
. This is not the best solution what I look for.
Also I found solution with reflection:
decoded := reflect.ValueOf(target).Convert(reflect.TypeOf(target))
// fmt.Printf("%T", decoded) == reflect.Value
But I couldn't understand how to get struct from reflect.Value
to pass it to json.Unmarshal
function.
How this decode
function will be used?
I have multiple requests in different structures. I can determine what struct I should use to decode request. I have mapping between request type and structure like this map[RequestMethod]interface{}
.
Schematic version looks like this:
func hydrate(data []byte) (interface{}, error) {
var base baseResponse
if err := json.Unmarshal(data, &base); err != nil {
return nil, err
}
target, ok := methodsMap[Method(base.Method)]
if !ok {
return nil, errors.New("Trying to hydrate data with unknown method: " + base.Method)
}
decoded, err := decode(data, target) // Expected target type.
Added:
If we pass our target
to json.Unmarshal
without casting to it type we will obtain map
. Example:
func decode(data []byte, target interface{}) (interface{}, error) {
err := json.Unmarshal(data, &target)
// fmt.Printf("%T", target) == map[string]interface{} not struct.
Solution
Thanks to @icza we found solution:
func hydrate(data []byte) (interface{}, error) {
var base baseResponse
if err := json.Unmarshal(data, &base); err != nil {
return nil, err
}
target, ok := methodsMap[Method(base.Method)]
if !ok {
return nil, errors.New("Trying to hydrate data with unknown method: " + base.Method)
}
// Clone request draft struct.
decoded := reflect.New(reflect.ValueOf(target).Type()).Interface()
err := decode(data, decoded)
...
Related links:
<https://stackoverflow.com/questions/38829941/golang-interface-type-misunderstanding/38830638#38830638>
<https://stackoverflow.com/questions/37851500/how-to-copy-an-interface-value-in-go/37851764#37851764>
答案1
得分: 5
使用以下代码创建draft struct的副本并解组到其中:
t := reflect.TypeOf(methodsMap[Method(base.Method)])
pv := reflect.New(t)
err := json.Unmarshal(p, pv.Interface())
return pv.Elem().Interface(), err // pv.Elem()解引用指针
英文:
Use the following code to create a copy of the draft struct and unmarshal to it:
t := reflect.TypeOf(methodsMap[Method(base.Method)])
pv := reflect.New(t)
err := json.Unmarshal(p, pv.Interface())
return pv.Elem().Interface(), err // pv.Elem() dereferences ptr
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论