dtr84664 2016-06-08 22:04 采纳率: 100%
浏览 21
已采纳

在Go运行时解组为在运行时确定的结构数组

I'm trying to dynamically create a slice of structs that I can marshal my data into, but doing it at runtime based on some unknown struct type. I'm doing this because I want to have one common bit of code that can unmarshal anything that implements a specific interface.

e.g. (pseudo code)

func unmarshalMyData(myInterface MyInterface, jsonData []byte) {
   targetSlice := myInterface.EmptySlice()
   json.Unmarshal(jsonData, &targetSlice)
}

I've tried several different alternatives. The one that seems the most promising is using the reflect package to construct the slice. Unfortunately, after unmarshalling, the dynamically created slice has a type of []interface{}. If I print out the type of the dynamically created slice before unmarshalling it prints []*main.myObj. Can anyone explain why? See playground link: https://play.golang.org/p/vvf1leuQeY

Is there some other way to dynamically create a slice of structs that unmarshals correctly?

I'm aware of json.RawMessage, but there are a few reasons I can't use it... there is no "type" field in my json. Also, the code where I am unmarshalling has no compile time knowledge of the struct that it is unmarshalling. It only knows that the struct implements a specific interface.

Some code that baffles me as to why dynamically created slice doesn't maintain its type after unmarshalling:

package main

import (
    "encoding/json"
    "fmt"
    "reflect"
)

func main() {
    input := `[{"myField":"one"},{"myField":"two"}]`
    myObjSlice := []*myObj{}
    fmt.Printf("Type of myObjSlice before unmarshalling %T
", myObjSlice)
    err := json.Unmarshal([]byte(input), &myObjSlice)
    if err != nil {
        panic(err)
    }
    fmt.Printf("Type of myObjSlice after unmarshalling %T
", myObjSlice)

    myConstructedObjSlice := reflect.MakeSlice(reflect.SliceOf(reflect.TypeOf(&myObj{})), 0, 0).Interface()
    fmt.Printf("Type of myConstructedObjSlice before unmarshalling %T
", myConstructedObjSlice)
    err = json.Unmarshal([]byte(input), &myConstructedObjSlice)
    if err != nil {
        panic(err)
    }
    fmt.Printf("Type of myConstructedObjSlice after unmarshalling %T
", myConstructedObjSlice)
}

type myObj struct {
    myField string
}

The output:

Type of myObjSlice before unmarshalling []*main.myObj
Type of myObjSlice after unmarshalling []*main.myObj
Type of myConstructedObjSlice before unmarshalling []*main.myObj
Type of myConstructedObjSlice after unmarshalling []interface {}
  • 写回答

1条回答 默认 最新

  • douwei1921 2016-06-08 22:27
    关注

    You're building a []*myObj using reflect, but you're then passing an *interface{} to json.Unmarshal. The json package sees the target of the pointer as the type interface{}, and therefore uses its default types to unmarshal into. You need to create a pointer to the slice type you create, so the call to the Interface() method returns the exactly type you want to unmarshal into, which is *[]*myObj.

    sliceType := reflect.SliceOf(reflect.TypeOf(&myObj{}))
    slicePtr := reflect.New(sliceType)
    
    err = json.Unmarshal([]byte(input), slicePtr.Interface())
    
    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥15 孟德尔随机化结果不一致
  • ¥20 求用stm32f103c6t6在lcd1206上显示Door is open和password:
  • ¥15 apm2.8飞控罗盘bad health,加速度计校准失败
  • ¥15 求解O-S方程的特征值问题给出边界层布拉休斯平行流的中性曲线
  • ¥15 谁有desed数据集呀
  • ¥20 手写数字识别运行c仿真时,程序报错错误代码sim211-100
  • ¥15 关于#hadoop#的问题
  • ¥15 (标签-Python|关键词-socket)
  • ¥15 keil里为什么main.c定义的函数在it.c调用不了
  • ¥50 切换TabTip键盘的输入法