从通用且动态的 go 地图获取内容的最佳方式是什么?

Whats the best way to get content from a generic and somehow dynamic go map?

我将这个 json 转换为:

var leerCHAT []interface{}

但我正在经历疯狂的篮球,以到达地图内部地图和地图内部疯狂的地图上的任何点,特别是因为一些结果是不同的内容。 这是 Json

[
   null,
   null,
   "hub:zWXroom",
   "presence_diff",
   {
      "joins":{
         "f718a187-6e96-4d62-9c2d-67aedea00000":{
            "metas":[
               {
                  "context":{},
                  "permissions":{},
                  "phx_ref":"zNDwmfsome=",
                  "phx_ref_prev":"zDMbRTmsome=",
                  "presence":"lobby",
                  "profile":{},
                  "roles":{}
               }
            ]
         }
      },
      "leaves":{}
   }
]

我需要进入配置文件然后里面有一个“DisplayName”字段。

所以我一直在做疯狂的黑客..即使这样我也被卡在了一半...

首先是一个数组,所以我可以做一些事情[elementnumber] 然后是棘手的映射开始的时候...... 抱歉所有打印等是为了调试并查看我返回的元素数量。

if leerCHAT[3] == "presence_diff" {
                var id string
                presence := leerCHAT[4].(map[string]interface{})
                log.Printf("algo: %v", len(presence))
                log.Printf("algo: %s", presence["joins"])
                vamos := presence["joins"].(map[string]interface{})
                for i := range vamos {
                    log.Println(i)
                    id = i
                }
                log.Println(len(vamos))

                vamonos := vamos[id].(map[string]interface{})
                log.Println(vamonos)
                log.Println(len(vamonos))

                metas := vamonos["profile"].(map[string]interface{})   \\ I get error here..

                log.Println(len(metas))
            }

到目前为止,我可以一直看到 meta:{...} 但无法继续将我的 hacky 代码变成我需要的东西。

注意:由于在 Joins: 之后和 metas: 之前的 id 是动态的,所以我必须以某种方式获取它,因为它始终只是一个元素,所以我使用 for range 循环来获取它。

索引 3 处的数组元素描述了索引 4 处变体 JSON 的类型。

以下是解码 JSON 到 Go 值的方法。首先,为 JSON:

的每个变体部分声明 Go 类型
type PrescenceDiff struct {
     Joins map[string]*Presence // declaration of Presence type to be supplied
     Leaves map[string]*Presence
}

type Message struct {
     Body string
}

声明一个将类型字符串关联到 Go 类型的映射:

var messageTypes = map[string]reflect.Type{
    "presence_diff": reflect.TypeOf(&PresenceDiff{}),
    "message":       reflect.TypeOf(&Message{}),
    // add more types here as needed
}

将变体部分解码为raw message。使用索引 3 处元素中的名称创建适当 Go 类型的值并解码为该值:

func decode(data []byte) (interface{}, error) {
    var messageType string
    var raw json.RawMessage
    v := []interface{}{nil, nil, nil, &messageType, &raw}
    err := json.Unmarshal(data, &v)
    if err != nil {
        return nil, err
    }

    if len(raw) == 0 {
        return nil, errors.New("no message")
    }

    t := messageTypes[messageType]
    if t == nil {
        return nil, fmt.Errorf("unknown message type: %q", messageType)
    }

    result := reflect.New(t.Elem()).Interface()
    err = json.Unmarshal(raw, result)
    return result, err
}

使用type switches访问消息的变体部分:

defer ws.Close()

for {
    _, data, err := ws.ReadMessage()
    if err != nil {
        log.Printf("Read error: %v", err)
        break
    }

    v, err := decode(data)
    if err != nil {
        log.Printf("Decode error: %v", err)
        continue
    }

    switch v := v.(type) {
    case *PresenceDiff:
        fmt.Println(v.Joins, v.Leaves)
    case *Message:
        fmt.Println(v.Body)
    default:
        fmt.Printf("type %T not handled\n", v)
    }
}

Run it on the playground.