How to convert interface{} to map

85,744

Solution 1

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
   }
}

Solution 2

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)

Solution 3

This may help:

b := []byte(`{"keyw":"value"}`)

var f interface{}
json.Unmarshal(b, &f)

myMap := f.(map[string]interface{})

fmt.Println(myMap)
Share:
85,744
SamTech
Author by

SamTech

Updated on July 09, 2022

Comments

  • SamTech
    SamTech almost 2 years

    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.

  • cnicutar
    cnicutar almost 8 years
    Nice. I added the MapKeys to my answer part as you were posting yours!
  • SamTech
    SamTech almost 8 years
    Working absolutely fine. Thanks a lot.
  • SamTech
    SamTech almost 8 years
    Here struct could be any struct like Book, Auther, Publisher ... for type switching type of struct must be known, that i don't have.
  • cnicutar
    cnicutar almost 8 years
    @SamTech How is the type of the struct not "known"? You can just switch over all the types you want to handle.
  • SamTech
    SamTech almost 8 years
    I mean, how do i know whether i have to type switch passed interface to map[string]*Book or map[string]*Auther ?
  • cnicutar
    cnicutar almost 8 years
    @SamTech Just switch on both.