我正在尝试动态创建一个结构片段,我可以将我的数据封送到其中,但是在运行时根据一些未知的结构类型进行.我这样做是因为我希望有一个共同的代码可以解组任何实现特定接口的代码.
例如(伪代码)
func unmarshalMyData(myInterface MyInterface, jsonData []byte) {
targetSlice := myInterface.EmptySlice()
json.Unmarshal(jsonData, &targetSlice)
}
Run Code Online (Sandbox Code Playgroud)
我尝试过几种不同的选择.看起来最有希望的是使用reflect
包构建切片.不幸的是,在解组后,动态创建的切片的类型为[]interface{}
.如果我在解组之前打印出动态创建的切片的类型,则会打印出来[]*main.myObj
.有谁能解释为什么?请参阅游乐场链接:https://play.golang.org/p/vvf1leuQeY
有没有其他方法可以动态创建一个正确解组的结构片?
我知道json.RawMessage
,但有一些原因我无法使用它......我的json中没有"type"字段.此外,我解组的代码没有编译时知道它解组的结构.它只知道struct实现了一个特定的接口.
有些代码让我感到困惑,为什么动态创建的切片在解组后不会保持其类型:
package main
import (
"encoding/json"
"fmt"
"reflect"
)
func main() {
input := `[{"myField":"one"},{"myField":"two"}]`
myObjSlice := []*myObj{}
fmt.Printf("Type of myObjSlice before unmarshalling %T\n", myObjSlice)
err := json.Unmarshal([]byte(input), &myObjSlice)
if err != nil {
panic(err)
}
fmt.Printf("Type of myObjSlice after unmarshalling %T\n", myObjSlice)
myConstructedObjSlice := reflect.MakeSlice(reflect.SliceOf(reflect.TypeOf(&myObj{})), 0, 0).Interface()
fmt.Printf("Type of myConstructedObjSlice before unmarshalling %T\n", myConstructedObjSlice)
err = json.Unmarshal([]byte(input), &myConstructedObjSlice)
if err != nil {
panic(err)
}
fmt.Printf("Type of myConstructedObjSlice after unmarshalling %T\n", myConstructedObjSlice)
}
type myObj struct {
myField string
}
Run Code Online (Sandbox Code Playgroud)
输出:
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 {}
Run Code Online (Sandbox Code Playgroud)
你正在建立一个[]*myObj
使用反射,但你正在传递*interface{}
给json.Unmarshal
.json包将指针的目标视为类型interface{}
,因此使用其默认类型进行解组.您需要创建一个指向您创建的切片类型的指针,因此对该Interface()
方法的调用将返回您要解组的确切类型,即*[]*myObj
.
sliceType := reflect.SliceOf(reflect.TypeOf(&myObj{}))
slicePtr := reflect.New(sliceType)
err = json.Unmarshal([]byte(input), slicePtr.Interface())
Run Code Online (Sandbox Code Playgroud)