Reputation: 111
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
}
Upvotes: 6
Views: 3504
Reputation: 950
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 ;)
Upvotes: 4
Reputation: 79546
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
}
Upvotes: 9
Reputation: 101
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)
}
Upvotes: 10