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?
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{}
.Output:
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:Output (try it on the Go Playground):
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 thefor
loops to iterate over them and use type assertion on each of their elements. Also note that thejson
package unmarshals the numbers into values of typefloat64
and notint
(because not just integers can be in the JSON text sofloat64
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 callsrecover()
to catch this panic (try it on the Go Playground):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 befalse
(and will betrue
if type assertion holds).Try it on the Go Playground:
Because you have an array literal rather than an object, the best way to parse is by unmarshaling first to a slice of json.RawMessages, and then go through the fields in the resulting slice:
This gives the correct result:
contig 32 {[33 41 35] [44 34 42]}
Playground: https://play.golang.org/p/jcYvINkTTn
If you have control over the source of the JSON though, changing it to an object literal would be the most straightforward way to go about it.
Your JSON contains an array literal and you're trying to deserialize it as a struct. You need to change the JSON to an object literal where the keys are the property names of your struct.
If the JSON isn't something you have the ability to change, then you will need to deserialize it into an untyped array and perform your own transformation into the struct type.