Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/json/13.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/wix/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
golang unmarshal复杂json_Json_Go_Unmarshalling - Fatal编程技术网

golang unmarshal复杂json

golang unmarshal复杂json,json,go,unmarshalling,Json,Go,Unmarshalling,我有下面的JSON blob,我正在尝试将其解码为Go ["contig", "32", {"a":[33,41,35], "b":[44,34,42]}] 我相信我必须对JSON的数据结构建模。我尝试使用名为Line的结构: package main import ( "encoding/json" "fmt" ) type Line struct { Contig string Base string PopMap map[string][]int } f

我有下面的JSON blob,我正在尝试将其解码为Go

["contig", "32", {"a":[33,41,35], "b":[44,34,42]}]
我相信我必须对JSON的数据结构建模。我尝试使用名为
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)
}
我得到了以下错误:

{  map[]}
json: cannot unmarshal array into Go value of type main.Line
我做错了什么


您的JSON包含一个数组文本,您正试图将其反序列化为一个结构。您需要将JSON更改为对象文字,其中键是结构的属性名

j := []byte(`{
    "Contig": "contig",
    "Base": "32",
    "PopMap": {"a":[33,41,35], "b":[44,34,42]}
}`)

如果JSON不是您可以更改的内容,那么您需要将其反序列化为非类型化数组,并执行您自己到结构类型的转换。

因为您有一个数组文本而不是一个对象,所以最好的解析方法是首先对,然后遍历结果切片中的字段:

package main

import (
     "encoding/json"
     "fmt"
)


func main() {
    j := []byte(`["contig", "32", {"a":[33,41,35], "b":[44,34,42]}]`)

    var entries []json.RawMessage
    err := json.Unmarshal(j, &entries)
    if err != nil {
        fmt.Println(err)
    }

    var contig string
    var num string
    var obj struct {
        A []int `json:"a"`
        B []int `json:"b"`
    }

    err = json.Unmarshal(entries[0], &contig)
    err = json.Unmarshal(entries[1], &num)
    err = json.Unmarshal(entries[2], &obj)

    fmt.Println(contig)
    fmt.Println(num)
    fmt.Println(obj)
}
这将给出正确的结果:

contig
32
{[33 41 35][44 34 42]}

游乐场:


如果您可以控制JSON的源代码,那么将其更改为对象文字将是最简单的方法。

您指定的JSON输入是一个不同类型的数组,因此,您不能将其解组到
结构中,而只能解组到不同类型的片段中:
[]接口{}

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))
    for i, val := range nums {
        pops[i] = int(val.(float64))
    }
    l.PopMap[k] = pops
}

fmt.Printf("%+v", l)
输出(在上尝试):

一些注意事项:

“a”
“b”
的值的“内部”数组被解组为
[]接口{}
类型的值,您不能简单地将其转换为
[]int
[]float64
,因此
for
循环对其进行迭代,并在其每个元素上使用类型断言。还请注意,
json
包将数字解组为
float64
类型的值,而不是
int
(因为json文本中不仅可以包含整数,所以使用了
float64
,可以同时容纳这两种类型)

还要注意,在上面的示例中没有检查类型断言是否成功。如果解组数组少于3个元素,或者任何类型断言失败,则会发生运行时死机

使用
recover()
您可以添加一个
defer
函数,该函数调用
recover()
,以捕捉这种恐慌(在上尝试):

用支票编码 或者您可以添加类型断言的检查。类型断言有一个特殊的形式
v,ok=x.(T)
,当使用它时,它不会恐慌,但是如果类型断言不成立,
ok
将是
false
(如果类型断言成立,
true

请在以下网站上试用:

如果len(arr)<3{
返回
}
var ok bool
l:=行{PopMap:map[string][]int{}
如果l.Contig,ok=arr[0](字符串)!嗯{
返回
}
如果l.Base,ok=arr[1](字符串)!嗯{
返回
}
如果m,ok:=arr[2]。(map[string]接口{})!嗯{
返回
}否则{
对于k,v:=范围m{
var nums[]接口{}
如果nums,ok=v.([]接口{});!ok{
返回
}
pops:=制造([]整数,len(nums))
对于i,val:=范围nums{
如果f,ok:=val.(float64);!ok{
返回
}否则{
持久性有机污染物[i]=int(f)
}
}
l、 PopMap[k]=pops
}
}
格式打印F(“%+v”,l)

Go JSON是否能够覆盖列映射?(我希望像Json.NET这样的库中有这样的功能;我不确定在Go的实现中是否应该有这样的功能。)标记可以用来指定Json对象中应该使用哪个键来填充结构上的属性。不过,这对原始帖子中的JSON没有帮助。数组不是这种结构化数据的好格式,您必须记住,位置0中的项与位置1中的项具有完全不同的含义,以此类推。
{Contig:contig Base:32 PopMap:map[a:[33 41 35] b:[44 34 42]]}
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...
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)