Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to convert interface{} to map

I am trying to create a function that could accept following

*struct []*struct map[string]*struct 

Here struct could be any struct not just a specific one. Converting interface to *struct or []*struct is working fine. But giving error for map.

After reflect it shows it is map[] but giving error when try to iterate over range.

Here is code

package main  import (     "fmt"     "reflect" )  type Book struct {     ID     int     Title  string     Year   int }  func process(in interface{}, isSlice bool, isMap bool) {     v := reflect.ValueOf(in)      if isSlice {         for i := 0; i < v.Len(); i++ {             strct := v.Index(i).Interface()             //... proccess struct         }         return     }      if isMap {         fmt.Printf("Type: %v\n", v)     // map[]         for _, s := range v {           // Error: cannot range over v (type reflect.Value)             fmt.Printf("Value: %v\n", s.Interface())         }     }     }  func main() {     b := Book{}     b.Title = "Learn Go Language"     b.Year = 2014     m := make(map[string]*Book)     m["1"] = &b      process(m, false, true) } 

Is there any way to convert interface{} to map and iterate or get it's elements.

like image 439
SamTech Avatar asked Jul 04 '16 13:07

SamTech


People also ask

What is interface {} Golang?

interface{} means you can put value of any type, including your own custom type. All types in Go satisfy an empty interface ( interface{} is an empty interface). In your example, Msg field can have value of any type.

What is MAP string string in Golang?

Golang Maps is a collection of unordered pairs of key-value. It is widely used because it provides fast lookups and values that can retrieve, update or delete with the help of keys. It is a reference to a hash table.


2 Answers

If the map value can be any type, then use reflect to iterate through the map:

if v.Kind() == reflect.Map {     for _, key := range v.MapKeys() {         strct := v.MapIndex(key)         fmt.Println(key.Interface(), strct.Interface())     } } 

playground example

If there's a small and known set of struct types, then a type switch can be used:

func process(in interface{}) {   switch v := in.(type) {   case map[string]*Book:      for s, b := range v {          // b has type *Book          fmt.Printf("%s: book=%v\n" s, b)      }   case map[string]*Author:      for s, a := range v {          // a has type *Author          fmt.Printf("%s: author=%v\n" s, a)      }    case []*Book:      for i, b := range v {          fmt.Printf("%d: book=%v\n" i, b)      }    case []*Author:      for i, a := range v {          fmt.Printf("%d: author=%v\n" i, a)      }    case *Book:      fmt.Ptintf("book=%v\n", v)    case *Author:      fmt.Printf("author=%v\n", v)    default:      // handle unknown type    } } 
like image 160
Bayta Darell Avatar answered Sep 17 '22 14:09

Bayta Darell


You don't need reflect here. Try:

v, ok := in.(map[string]*Book) if !ok {     // Can't assert, handle error. } for _, s := range v {     fmt.Printf("Value: %v\n", s) } 

Same goes for the rest of your function. It looks like you're using reflection when you would be better served by a type switch.


Alternatively, if you insist on using reflection here (which doesn't make a lot of sense) you can also use Value.MapKeys with the result from your ValueOf (see the answer https://stackoverflow.com/a/38186057/714501)

like image 26
cnicutar Avatar answered Sep 18 '22 14:09

cnicutar