英文:
JSON decode with flexible type
问题
我需要以一种灵活的方式指定解码JSON数据的类型,这意味着类型需要在运行时指定。
考虑以下代码片段:http://play.golang.org/p/F-Jy4ufMPz
s := `{"b":[{"x":9},{"x":4}]}`
var a struct {
B []interface{}
}
err := json.Unmarshal([]byte(s), &a)
if err != nil {
panic(err)
}
fmt.Println(a)
这将产生{[map[x:9] map[x:4]]}
。我想要解码为一个特定类型(结构体)的数组,而不是[]interface{}
,而且不需要在编译时指定。
有没有办法在不事先创建数组的情况下实现这一点?(返回的项数是未知的)
我目前能想到的唯一方法是稍后再次对返回的映射进行编码,并将其解码为指定的类型,这将创建不必要的处理开销。
英文:
I need to specify a type for decoding JSON data in a flexible manner, meaning the type needs to be specified at runtime.
Consider this snippet: http://play.golang.org/p/F-Jy4ufMPz
s := `{"b":[{"x":9},{"x":4}]}`
var a struct {
B []interface{}
}
err := json.Unmarshal([]byte(s), &a)
if err != nil {
panic(err)
}
fmt.Println(a)
Which will produce {[map[x:9] map[x:4]]}
. I want to decode to an array of a specific (struct) type instead of []interface{}
, without specifying it at compile time.
Is that somehow possible without creating the array up front? (the number of returned items is unknown)
The only way I can think of right now is to encode the returned maps again later, and decode them to the specified type, which would create unnecessary processing overhead.
答案1
得分: 5
如果在编译时没有指定它,你仍然需要在某个地方指定它。
如果在检索Json数据之前指定了它,你可以简单地使用switch case将其解组为所需的对象。
如果在Json数据中指定了它,你可以将"灵活"部分编组为json.RawMessage
,在确定适合的结构类型后进行处理:
package main
import (
"encoding/json"
"fmt"
)
var s = `{"type":"structx", "data":{"x":9,"xstring":"This is structX"}}`
type JsonStruct struct {
Type string
Data json.RawMessage
}
type StructX struct {
X float64
Xstring string
}
type StructY struct {
Y bool
}
func main() {
var a *JsonStruct
err := json.Unmarshal([]byte(s), &a)
if err != nil {
panic(err)
}
switch a.Type {
case "structx":
// 将RawMessage部分解组为StructX
var s *StructX
json.Unmarshal([]byte(a.Data), &s)
if err != nil {
panic(err)
}
fmt.Println(s)
case "structy":
// 对structY执行相同的操作
}
}
英文:
If not specifying it at compile time, you still need to specify it somewhere.
If specified before the retrieval of the Json data, you can simply do a switch case, Unmarshalling it to your desired object.
If specified within the Json data, you can marshal the "flexible" part into a json.RawMessage
to process it after you've decided what type of struct is suitable:
package main
import (
"encoding/json"
"fmt"
)
var s = `{"type":"structx", "data":{"x":9,"xstring":"This is structX"}}`
type JsonStruct struct {
Type string
Data json.RawMessage
}
type StructX struct {
X float64
Xstring string
}
type StructY struct {
Y bool
}
func main() {
var a *JsonStruct
err := json.Unmarshal([]byte(s), &a)
if err != nil {
panic(err)
}
switch a.Type {
case "structx":
// We Unmashal the RawMessage part into a StructX
var s *StructX
json.Unmarshal([]byte(a.Data), &s)
if err != nil {
panic(err)
}
fmt.Println(s)
case "structy":
// Do the same but for structY
}
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论