【问题标题】:How can I reverse map using reflection如何使用反射反转地图
【发布时间】:2020-10-22 19:54:14
【问题描述】:

我正在学习 Go 中的 reflect 并尝试实现获取 map 并返回另一个 map 的函数,其中键是值,值是键。

例子:

m := map[string]int{"one": 1, "two": 2}
fmt.Println(ReverseMap(m)) // {1: "one", 2: "two"}

这是我的代码:

func ReverseMap(in interface{}) interface{} {

    var out reflect.Value
    v := reflect.ValueOf(in)
    if v.Kind() == reflect.Map {
        for idx, key := range v.MapKeys() {
            value := v.MapIndex(key)
            if idx == 0 {
                mapType := reflect.MapOf(reflect.TypeOf(value), reflect.TypeOf(key))
                out = reflect.MakeMap(mapType)
            }
            out.SetMapIndex(value, key)
        }
    }
    return out
}

此代码panic 有错误:

恐慌:reflect.Value.SetMapIndex:int 类型的值不能分配给类型 reflect.Value

我认为这个错误的原因是out变量的声明,但是我不知道如何正确声明它,如果我不知道这个变量的类型。

我该如何解决这个错误?

【问题讨论】:

    标签: dictionary go reflection


    【解决方案1】:

    keyvalue 的类型为 reflect.Value,因此将它们传递给 reflect.TypeOf() 将不会返回映射的键和值类型(stringint)的类型描述符,而是reflect.Value 类型本身的类型描述符。

    而是简单地调用他们的Value.Type() 方法:

    mapType := reflect.MapOf(value.Type(), key.Type())
    

    有了它,它(几乎)可以工作和打印(在Go Playground 上试试):

    map[1:one 2:two]
    

    我写“几乎”是因为您返回的是 reflect.Value,而不是 map。但是,如果将 reflect.Value 传递给 fmt 包,它会打印包装在其中的值:

    如果操作数是 reflect.Value,则操作数被它所持有的具体值替换,并按照下一条规则继续打印。

    所以你应该在返回之前在out上调用Value.Interface()

    如果种类不是地图,提前返回比较容易,所以你可以在此之后立即创建地图:

    func ReverseMap(in interface{}) interface{} {
        v := reflect.ValueOf(in)
        if v.Kind() != reflect.Map {
            return nil
        }
    
        mapType := reflect.MapOf(v.Type().Elem(), v.Type().Key())
        out := reflect.MakeMap(mapType)
    
        for _, key := range v.MapKeys() {
            out.SetMapIndex(v.MapIndex(key), key)
        }
    
        return out.Interface()
    }
    

    Go Playground 上试试这个变体。

    另一种方法可能是使用Value.MapRange()

    for iter := v.MapRange(); iter.Next(); {
        out.SetMapIndex(iter.Value(), iter.Key())
    }
    

    Go Playground 上试试这个变体。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-11-21
      • 1970-01-01
      • 2018-01-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-10-03
      相关资源
      最近更新 更多