golang unmarshal复杂的json [英] golang unmarshal complex json

查看:213
本文介绍了golang unmarshal复杂的json的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有以下的JSON blob,我试图将它解码为Go。

  [contig, 32,{a:[33,41,35],b:[44,34,42]}] 

我相信我必须建模JSON的数据结构。我尝试使用一个名为 Line 的结构:

  package main 

导入(
encoding / json
fmt


类型线结构{
重叠字符串
基本字符串
PopMap map [string] [] int
}

func main(){
j:= [] byte(`[contig,32 ,{a:[33,41,35],b:[44,34,42]}]`)
var dat Line
err:= json.Unmarshal(j, & dat)
fmt.Println(dat)
fmt.Println(err)
}

我得到以下错误:

  {map []} 
json:can not unmarshal array into Go value of main.Line

我做错了什么?



链接到用于尝试代码的沙箱

解决方案

您指定的JSON输入是一个不同类型的数组,因此您无法将它解组为结构,但只能分成不同的类型: [] interface {}

  in:=`[contig,32,{a:[33,41,35],b:[44,34,42]}]`

var arr [] interface {}
if err:= json.Unmarshal([] byte(in),& arr); err!= nil {
panic(err)
}
fmt.Println(arr)

输出:

  [contig 32 map [a:[33 41 35] b:[44 34 42]]] 



填充 struct



好的,你现在有了值,只是不在你想要的 struct 中。您可以使用键入断言来获取您想要的类型:

  l:= Line {PopMap:map [string] [] int {}} 
l.Contig = arr [0]。(string)
l.Base = arr [1]。(string)

m:= arr [2]。(map [string] interface {})
for k,v:= range m {
nums:= v。([] interface {})
pops:= make([] int,len(nums))$ b $ for i,val:= range nums {
pops [i] = int(val。(float64))
}
l.PopMap [k] = pops
}

fmt.Printf( %+ v,l)

输出(在 Go Playground ):

  { Contig:contig Base:32 PopMap:map [a:[33 41 35] b:[44 34 42]]} 

值的内部数组a

code>和b被解组为 []接口类型的值{} 你不能简单地转换为 [] int [] float64 因此 for 循环遍历它们,并在每个元素上使用类型断言。另请注意, json 包会将数字编组为< float64 类型的值,而不是 int (因为不只是整数可以在JSON文本中,所以使用 float64 ,它可以同时容纳这两者)。



还要注意,在上例中没有检查类型断言的成功。如果unmarshaled数组少于3个元素,或者任何类型断言失败,就会发生运行时恐慌。



使用 recover()你可以添加一个调用 recover()的 defer 函数, 来捕捉这种恐慌(在去游乐场上试试):

 延迟func(){
如果r:= recover(); r!= nil {
fmt.Println(解组失败)
}
}()

l:=行{PopMap:map [string] [ ] int {}}
// ...以下代码使用类型断言
//并将值存储到...

$ b

带检查的代码



或者您可以为类型断言添加检查。类型断言有一个特殊的形式 v,ok = x。(T)它在使用时永远不会发生混乱,而是如果类型断言不成立, ok 将会是 false (并且如果类型断言成立,将会是 true )。



去游乐场试试:

  if len(arr)< 3 {
return
}
var ok bool
l:= Line {PopMap:map [string] [] int {}}
如果l.Contig,ok = ARR [0](字符串)。 !ok {
return
}
if l.Base,ok = arr [1]。(string); !ok {
return
}
if m,ok:= arr [2]。(map [string] interface {}); !ok {
return
} else {
for k,v:= range m {
var nums [] interface {}
if nums,ok = v。 ([]接口{}); !ok {
return
}
pops:= make([] int,len(nums))$ b $ for i,val:= range nums {
if f ,ok:= val。(float64); !ok {
return
} else {
pops [i] = int(f)
}
}
l.PopMap [k] = pops


$ b $ f mt.Printf(%+ v,l)


I have the following JSON blob, and I'm trying to decode it into Go.

["contig", "32", {"a":[33,41,35], "b":[44,34,42]}]

I believe that I have to model the data structure of the JSON. I tried using a struct called Line:

package main

import (
"encoding/json"
"fmt"
)

type Line struct {
    Contig string
    Base   string
    PopMap map[string][]int
}

func main() {
    j := []byte(`["contig", "32", {"a":[33,41,35], "b":[44,34,42]}]`)
    var dat Line
    err := json.Unmarshal(j, &dat)
    fmt.Println(dat)
    fmt.Println(err)
}

I got the following error:

{  map[]}
json: cannot unmarshal array into Go value of type main.Line

What am I doing wrong?

Link to sandbox for trying out code

解决方案

The JSON input you specified is an array of different types, so as it is, you can't unmarshal it into a struct, but only into a slice of different types: []interface{}.

in := `["contig", "32", {"a":[33,41,35], "b":[44,34,42]}]`

var arr []interface{}
if err := json.Unmarshal([]byte(in), &arr); err != nil {
    panic(err)
}
fmt.Println(arr)

Output:

[contig 32 map[a:[33 41 35] b:[44 34 42]]]

Filling the struct

Good, you now have the values, just not in the struct you want them to be. You can use type assertion to obtain the types you want:

l := Line{PopMap: map[string][]int{}}
l.Contig = arr[0].(string)
l.Base = arr[1].(string)

m := arr[2].(map[string]interface{})
for k, v := range m {
    nums := v.([]interface{})
    pops := make([]int, len(nums))
    for i, val := range nums {
        pops[i] = int(val.(float64))
    }
    l.PopMap[k] = pops
}

fmt.Printf("%+v", l)

Output (try it on the Go Playground):

{Contig:contig Base:32 PopMap:map[a:[33 41 35] b:[44 34 42]]}

Some notes:

The "internal" arrays of the values of "a" and "b" are unmarshaled into values of type []interface{} which you cannot simply convert to []int or []float64 hence the for loops to iterate over them and use type assertion on each of their elements. Also note that the json package unmarshals the numbers into values of type float64 and not int (because not just integers can be in the JSON text so float64 is used which can accommodate both).

Also note that the success of type assertions are not checked in the above example. If the unmarshaled array has less than 3 elements, or any of the type assertion fails, a runtime panic occurs.

Using recover()

You can add a defer function which calls recover() to catch this panic (try it on the Go Playground):

defer func() {
    if r := recover(); r != nil {
        fmt.Println("Failed to unmarshal")
    }
}()

l := Line{PopMap: map[string][]int{}}
// ...and here comes the code that uses type assertions
// and stores values into...

Code with checks

Or you can add checks for the type assertions. The type assertion has a special form v, ok = x.(T) which when used never panics, but rather if the type assertion doesn't hold, ok will be false (and will be true if type assertion holds).

Try it on the Go Playground:

if len(arr) < 3 {
    return
}
var ok bool
l := Line{PopMap: map[string][]int{}}
if l.Contig, ok = arr[0].(string); !ok {
    return
}
if l.Base, ok = arr[1].(string); !ok {
    return
}
if m, ok := arr[2].(map[string]interface{}); !ok {
    return
} else {
    for k, v := range m {
        var nums []interface{}
        if nums, ok = v.([]interface{}); !ok {
            return
        }
        pops := make([]int, len(nums))
        for i, val := range nums {
            if f, ok := val.(float64); !ok {
                return
            } else {
                pops[i] = int(f)
            }
        }
        l.PopMap[k] = pops
    }
}

fmt.Printf("%+v", l)

这篇关于golang unmarshal复杂的json的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆