The challenge of type asserting []interface{} to string slices.
- Posted by Michael MacDonald
- on Nov, 12, 2019
- in Go
- Blog No Comments.
When working with JSON data it can be easy to silently miss converting data, if one is not doing the typical unmarshalling into a well defined struct but instead into a generic map[string]interface{}
.
Given the following data block:
var jsonBytes = []byte(` { "data": [ "one", "two", "three" ] } `)
We can unmarshal it via
var jsonBlob map[string]interface{} err := json.Unmarshal(jsonBytes, &jsonBlob) if err != nil { fmt.Println("error:", err) }
If we then try and extract the data element and convert it to a slice of strings via a straightforward type assertion:
data := jsonBlob["data"].([]string) // or as a two step process data := jsonBlob["data"] dataSlice := data.([]string)
This ends up causing a panic:
panic: interface conversion: interface {} is []interface {}, not []string
Sometimes we get ‘clever’ and guard our type assertions like:
if data, ok := jsonBlob["data"].([]string); ok { // do something with data }
This sort of cleverness comes back to bite us when it silently never executes the inner code block. At least it didn’t panic.
What are we to do when we know we’re getting a string slice from the JSON block? It actually isn’t too difficult, we just let go know that this is an interface slice and range over it copying the data into a predefined slice variable:
var dataSlice []string for _, v := range a["data"].([]interface{}) { if s, ok := v.(string); ok { dataSlice = append(dataSlice, s) } }
Example on the Go playground: https://play.golang.org/p/MEdGhEzh6BE
Related
Comments & Responses
Recent Posts
- The shape of structured data
- Writing very small executable
- The challenge of type asserting []interface{} to string slices.
- Serializing/Deserializing a complex GO struct to store externally (i.e. in a database, redis, or text file)
- Fun with golang, Google Maps api, and proxying requests