I can decode json strings to a map with go language like this:
func main(){
date := []byte(`{"127.1":{"host":"host1","list":["list123","list456"]},"127.2":{"host":"host2","list":["list223","list256"]}}`)
var x interface{}
json.Unmarshal(date, &x)
t := x.(map[string]interface{})
var aa []interface{}
aa = (t["127.2"].(map[string]interface{})["list"])
for _, v := range aa {
fmt.Println(v.(string))
}
}
but I wonder how to decode it to a sync.Map in Go1.9. I have tried many ways but failed, can anyone help me?
I tried like this:
func main(){
date := []byte(`{"127.1":{"host":"host1","list":["list123","list456"]},"127.2":{"host":"host2","list":["list223","list256"]}}`)
var x interface{}
json.Unmarshal(date, &x)
t := x.((sync.Map)[string]interface{}) //compile error
}
Also I tried like this:
func main(){
date := []byte(`{"127.1":{"host":"host1","list":["list123","list456"]},"127.2":{"host":"host2","list":["list223","list256"]}}`)
var x sync.Map
json.Unmarshal(date, &x)
fmt.Println(x) // but the map has nothing
}
Golang provides multiple APIs to work with JSON including to and from built-in and custom data types using the encoding/json package. To parse JSON, we use the Unmarshal() function in package encoding/json to unpack or decode the data from JSON to a struct.
To convert a json to a map in Golang, use the json. Unmarshal() method. The Unmarshal() method parses the JSON-encoded data and stores the result in the value pointed to by the interface. If an interface is a nil or not a pointer, Unmarshal returns an InvalidUnmarshalError.
JSON has 3 basic types: booleans, numbers, strings, combined using arrays and objects to build complex structures. Go's terminology calls marshal the process of generating a JSON string from a data structure, and unmarshal the act of parsing JSON to a data structure.
To unmarshal a JSON array into a slice, Unmarshal resets the slice length to zero and then appends each element to the slice. As a special case, to unmarshal an empty JSON array into a slice, Unmarshal replaces the slice with a new empty slice.
How to convert JSON to Map in Go Language? To convert JSON String to Map object in Go language, import the package encode/json, call json.Unmarshall () function and pass the JSON String as byte array, and address of an empty map as arguments to the function. The function transforms the JSON string to map, and loads the result at given map address.
Golang json is one of the most used packages. JSON(JavaScript Object Notation) parsing a day to activity for a developer. Most of the API which developers parse is in JSON. Here we will see how we can parse JSON Object to Map. To convert a json to a map in Golang, use the json.Unmarshal () method.
This can be accomplished by Unmarshaling into a map [string]json.RawMessage. To further parse sendMsg, you could then do something like: For say, you can do the same thing and unmarshal into a string: EDIT: Keep in mind you will also need to export the variables in your sendMsg struct to unmarshal correctly.
The key-string will act as value identifier, telling the Go server what kind of value it is. By knowing what type of value, I can then proceed to JSON unmarshal the value into the correct type of struct.
In case you need a snippet to do it another way around
func (f Foo) MarshalJSON() ([]byte, error) {
tmpMap := make(map[YourTypeOfKey]YourTypeOfValue)
f.Range(func(k, v interface{}) bool {
tmpMap[k.(YourTypeOfKey)] = v.(YourTypeOfValue)
return true
})
return json.Marshal(tmpMap)
}
You cannot directly unmarshal into a sync.Map
, because sync.Map
has no exported fields (so the Unmarshaler doesn't have any way to store data in it), and it doesn't implement the json.Unmarshaler
interface.
So you'll have to handle this yourself, probably by including a sync.Map
in a type of your own, and implementing json.Unmarshaler
on that type:
type Foo struct {
sync.Map
}
func (f *Foo) UnmarshalJSON(data []byte) error {
var tmpMap map[string]interface{}
if err := json.Unmarshal(data, &tmpMap); err != nil {
return err
}
for key, value := range tmpMap {
f.Store(key, value)
}
return nil
}
Just adding to @jakub great answer about MarshalJSON
, you can also have a generic function that doesn't check the type (since json doesn't care either)
func MarshalJSON(m *sync.Map) ([]byte, error) {
tmpMap := make(map[interface{}]interface{})
m.Range(func(k, v interface{}) bool {
tmpMap[k] = v
return true
})
return json.Marshal(tmpMap)
}
This could take any kind of sync.Map
and just Marshal it.
To add to the UnMarshal
function from @Flimzy's answer, you can play a bit with the types by omitting the string part to make it more generics (pun intended, cry in corner):
func UnmarshalJSON(data []byte) (*sync.Map, error) {
var tmpMap map[interface{}]interface{}
m := &sync.Map{}
if err := json.Unmarshal(data, &tmpMap); err != nil {
return m, err
}
for key, value := range tmpMap {
m.Store(key, value)
}
return m, nil
}
In general it is good to play with the same Types when doing this sort of manipulation, because we are lazy and we don't want to rewrite functions ;)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With