Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to decode json strings to sync.Map instead of normal map in Go1.9?

Tags:

json

go

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
}
like image 778
zengxiaobai2 Avatar asked Sep 24 '17 13:09

zengxiaobai2


People also ask

How do I decode JSON in Golang?

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.

How do you Unmarshal a map?

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.

What is JSON marshal and Unmarshal?

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.

How does JSON Unmarshal work?

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 string to map in Go language?

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.

How to parse JSON object to map in Golang?

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.

How do I unmarshal a JSON message?

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.

What is the use of key-string in JSON?

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.


3 Answers

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)
}
like image 66
Jakub Sacha Avatar answered Oct 26 '22 23:10

Jakub Sacha


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
}
like image 26
Flimzy Avatar answered Oct 26 '22 22:10

Flimzy


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 ;)

like image 24
Seraf Avatar answered Oct 26 '22 22:10

Seraf