如何将 interface{} 转换为 map

新手上路,请多包涵

我正在尝试创建一个可以接受以下内容的函数

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

这里的结构可以是任何结构,而不仅仅是一个特定的结构。将接口转换为 *struct[]*struct 工作正常。但是给地图错误。

反射后它显示它是 map[] 但在尝试遍历范围时出错。

这是代码

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

有什么方法可以转换 interface{} 以映射和迭代或获取它的元素。

原文由 SamTech 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 1.6k
2 个回答

如果映射值可以是任何类型,则使用 reflect 遍历映射:

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

游乐场示例

如果有一小部分已知的结构类型,则可以使用 类型开关

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

原文由 Cerise Limón 发布,翻译遵循 CC BY-SA 3.0 许可协议

你不需要在这里反映。尝试:

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

其余功能也是如此。看起来您正在使用反射,而 类型 switch 会更好地为您提供服务。


或者,如果您坚持在此处使用反射(这没有多大意义),您也可以将 Value.MapKeys 与您的 ValueOf 的结果一起使用(参见答案 https://stackoverflow.com/a /38186057/714501 )

原文由 cnicutar 发布,翻译遵循 CC BY-SA 3.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题