如何将 interface 转换为地图

Posted

技术标签:

【中文标题】如何将 interface 转换为地图【英文标题】:How to convert interface to map如何将 interface 转换为地图 【发布时间】:2016-11-06 06:09:39 【问题描述】:

我正在尝试创建一个可以接受关注的函数

*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 转换为映射和迭代或获取它的元素。

【问题讨论】:

【参考方案1】:

这可能会有所帮助:

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

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

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

fmt.Println(myMap)

【讨论】:

【参考方案2】:

使用反射包将interface 转换为map 的另一种方法是使用MapRange

我引用:

MapRange 返回地图的范围迭代器。如果 v 的 Kind 是 不是地图。

调用 Next 来推进迭代器,调用 Key/Value 来访问每个条目。 当迭代器耗尽时,Next 返回 false。地图范围如下 与范围语句相同的迭代语义。

例子:

iter := reflect.ValueOf(m).MapRange()
for iter.Next() 
    key := iter.Key().Interface()
    value := iter.Value().Interface()
    ...

【讨论】:

【参考方案3】:

如果地图值可以是任何类型,则使用反射来遍历地图:

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

playground example

如果有一组已知的小型结构类型,则可以使用type switch:

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
   

【讨论】:

不错。当您发布您的答案时,我将MapKeys 添加到我的答案部分! 工作得很好。非常感谢。【参考方案4】:

你不需要在这里反思。试试:

v, ok := in.(map[string]*Book)
if !ok 
    // Can't assert, handle error.

for _, s := range v 
    fmt.Printf("Value: %v\n", s)

您的其他功能也是如此。当type switch 为您提供更好的服务时,您似乎正在使用反射。


或者,如果您坚持在这里使用反射(这没有多大意义),您也可以使用 Value.MapKeys 与您的 ValueOf 的结果(请参阅答案 https://***.com/a/38186057/714501)

【讨论】:

这里的结构可以是任何结构,如 Book、Auther、Publisher ... 用于类型切换的结构类型必须是已知的,我没有。 @SamTech 结构的类型如何不“已知”?您可以切换您想要处理的所有类型。 我的意思是,我怎么知道我是否必须输入 switch 传递的接口到 map[string]*Book 或 map[string]*Auther ? @SamTech 两者都打开。

以上是关于如何将 interface 转换为地图的主要内容,如果未能解决你的问题,请参考以下文章

UIView 的子类。如何通过 Interface Builder 添加?

如何将 UITableViewCell 的内容视图转换为 Interface Builder 中的普通 UIView?

Qt DBus 属性转换为地图

如何将地址转换为谷歌地图链接(不是地图)

如何将 bing 地图四键转换为墨卡托坐标

如何将 html 地图转换为图像(png 或 jpg )