我有一个枚举定义为

1
2
3
4
5
type MyEnum int

const(
   FirstEnum MyEnum = iota
)

然后,我有一个具有键值对"Key":"FirstEnum"的json。 我像这样解组。

1
2
3
var data map[string]interface{}
err := json.Unmarshal([]byte(json), &data)
x := data["key"].(MyEnum)

但是,当我运行此命令时,出现错误:

1
2
panic: interface conversion: interface {} is string, not ps.Protocol [recovered]
        panic: interface conversion: interface {} is string, not ps.Protocol

有没有一种方法可以像在Go中将枚举的字符串表示形式正常转换为枚举类型一样工作?

  • 首先,这完全不能与interface{}一起使用,因为解组器会将其解组为默认的字符串类型。 因此,您需要一个结构。 然后,您需要编写一个自定义UnmarshalJSON函数来为您处理事务。
  • 这听起来像很多工作...如何处理将json编组为自定义类型? 总是需要编写自定义解组器吗?
  • 只需阅读文档。 声明一个结构,创建一个指向结构实例的指针,然后直接在Unmarshal中使用它
  • 您不一定总是需要编写自定义拆组器。 仅当您想要自定义行为时。

我发现了一些类似的方式(至少适用于我目前的情况):

string用于类似enum的常量:

1
2
3
4
5
type MyEnum string

const(
   FirstEnum MyEnum ="FirstEnum"
)

现在,使用解码json自定义类型,如此处所述。

1
2
data := MyJsonStruct{}
err := json.Unmarshal([]byte(json), &data)

MyJsonStruct看起来像:

1
2
3
type MyJsonStruct struct {
    Key MyEnum
}

然后,可以使MyJsonStruct实现Unmarshaler接口,以便可以验证给定的值。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
func (s *MyJsonStruct) UnmarshalJSON(data []byte) error {
    // Define a secondary type so that we don't end up with a recursive call to json.Unmarshal
    type Aux MyJsonStruct;
    var a *Aux = (*Aux)(s);
    err := json.Unmarshal(data, &a)
    if err != nil {
        return err
    }

    // Validate the valid enum values
    switch s.Key {
    case FirstEnum, SecondEnum:
        return nil
    default:
        s.Key =""
        return errors.New("invalid value for Key")
    }
}

操场

  • 如果您愿意在Go中使用字符串类型,这确实是最简单的方法。
  • 如果字符串与枚举值之一不匹配,则此方法似乎不会引发任何错误。