地图键为结构时的元帅/非元帅问题

时间:2019-03-25 10:03:51

标签: go

我定义了一个名为Student的结构和一个名为score的映射。 数据结构如下所示:

type Student struct {
    CountryID int
    RegionID  int
    Name      string
}

stu := Student{111, 222, "Tom"}
score := make(map[Student]int64)
score[stu] = 100

我正在使用json.Marshal将分数编组为json,但是我不能使用json.Unmarshal解组此json。下面是我的代码。我正在使用GetMarshableObject函数将struct Student转换为可沼泽的字符串。 谁能告诉我如何处理此json以将其解组回地图得分。

package main

import (
    "encoding/json"
    "fmt"
    "os"
    "reflect"
)

type Student struct {
    CountryID int
    RegionID  int
    Name      string
}

func GetMarshableObject(src interface{}) interface{} {
    t := reflect.TypeOf(src)
    v := reflect.ValueOf(src)
    kind := t.Kind()
    var result reflect.Value
    switch kind {
    case reflect.Map:
        //Find the map layer count
        layer := 0
        cur := t.Elem()
        for reflect.Map == cur.Kind() {
            layer++
            cur = cur.Elem()
        }
        result = reflect.MakeMap(reflect.MapOf(reflect.TypeOf("a"), cur))
        for layer > 0 {
            result = reflect.MakeMap(reflect.MapOf(reflect.TypeOf("a"), result.Type()))
            layer--
        }
        keys := v.MapKeys()
        for _, k := range keys {
            value := reflect.ValueOf(GetMarshableObject(v.MapIndex(k).Interface()))
            if value.Type() != result.Type().Elem() {
                result = reflect.MakeMap(reflect.MapOf(reflect.TypeOf("a"), value.Type()))
            }
            result.SetMapIndex(reflect.ValueOf(fmt.Sprintf("%v", k)), reflect.ValueOf(GetMarshableObject(v.MapIndex(k).Interface())))
        }
    default:
        result = v
    }
    return result.Interface()
}

func main() {
    stu := Student{111, 222, "Tom"}
    score := make(map[Student]int64)
    score[stu] = 100

    b, err := json.Marshal(GetMarshableObject(score))
    if err != nil {
        fmt.Println("error:", err)
    }
    os.Stdout.Write(b) //{"{111 222 Tom}":100}

    scoreBak := make(map[Student]int64)
    if err = json.Unmarshal(b, &scoreBak); nil != err {
        fmt.Println("error: %v", err) // get error here: cannot unmarshal object into Go value of type map[main.Student]int64
    }
}

1 个答案:

答案 0 :(得分:5)

来自docs

  

地图的键类型必须是字符串,整数类型或   实现encoding.TextMarshaler。

func (s Student) MarshalText() (text []byte, err error) {
    type noMethod Student
    return json.Marshal(noMethod(s))
}

func (s *Student) UnmarshalText(text []byte) error {
    type noMethod Student
    return json.Unmarshal(text, (*noMethod)(s))
}

例如,我使用encoding/json将Student值转换为json对象键,但这不是必需的,您可以选择自己的格式。

https://play.golang.org/p/4BgZn4Y37Ww