16

I want to parse a JSON file to a map[string]interface{}:

var migrations map[string]interface{}
json.Unmarshal(raw, &migrations)

fmt.Println(migrations["create_user"])

But I modified my code to point data to interface{}:

var migrations interface{}
json.Unmarshal(raw, &migrations)

// compile wrong here
fmt.Println(migrations["create_user"])

I don't understand much about difference between map[string]interface{} and interface{} in above case.

Himanshu
  • 12,071
  • 7
  • 46
  • 61
Trần Kim Dự
  • 5,872
  • 12
  • 55
  • 107

2 Answers2

46

The difference between those two types is just what it seems:

  1. interface{} is the "any" type, since all types implement the interface with no functions.

  2. map[string]interface{} is a map whose keys are strings and values are any type.

When unmarshaling a byte array from JSON into memory it's easiest to use the interface{} type, since it can store any type of JSON document (objects, arrays, primitives, etc.); however, it may require more reflection to handle the underlying data. Using a map[string]interface{} is common when you know the JSON document is an object and []interface{} is common when you know the document is an array.

However, the best approach for unmarshaling JSON - especially when you know the structure of the documents ahead of time - is to define and use custom struct types that describe the data exactly. This way you can avoid any reflection and improve the legibility of your code.

maerics
  • 151,642
  • 46
  • 269
  • 291
  • thanks. The problem I meet is: I have an array of "object": each object is on different type, so different struct, depend on field "type". So I must get each block separate before parsing. – Trần Kim Dự Feb 26 '18 at 18:54
16

It is because by default you need to type assert interface{} to get the underlying value of map[string]interface{}.

As per GoLang Specification

For an expression x of interface type and a type T, the primary expression

x.(T)

asserts that x is not nil and that the value stored in x is of type T. The notation x.(T) is called a type assertion.

Also Unmarshal function requires pointer to migration of type interface{} or map[string]interface{}

var migrations interface{}
json.Unmarshal(raw, &migrations)

fmt.Println(migrations.(interface{}).(map[string]interface{})["create_user"])

Since migrations is not a map. So you cannot use its key to get the value. Interface{} don't have keys

Himanshu
  • 12,071
  • 7
  • 46
  • 61
  • Can I asked a question. If an object have similar field with one struct, can we cast that object to that struct. thanks. – Trần Kim Dự Feb 26 '18 at 12:59
  • yes we can Unmarshal the data into struct having tags for json. Checkout this [link](https://gobyexample.com/json) – Himanshu Feb 26 '18 at 13:03