如何根据字符串表示获取 Protobuf 枚举值?

huangapple go评论250阅读模式
英文:

How to get a Protobuf enum value from its string representation?

问题

你可以使用Parse方法来从字符串中获取Protobuf枚举元素的值。以下是示例代码:

  1. status := testPB.Status(testPB.Status_value["ENABLED"])

这将返回与字符串"ENABLED"对应的Protobuf枚举元素。请确保在使用之前导入正确的包并进行适当的类型转换。

英文:

I can get the string value of a Protobuf enum with this instruction:

  1. str := testPB.Status_ENABLED.String()

How can I perform the inverse operation? (from a string, get the enum element).

答案1

得分: 6

生成的代码中有一个名为<EnumName>_value的映射,类型为map[string]int32。然后,您可以将数值转换为实际定义的类型:

  1. num := testPB.Status_value[str]
  2. v := testPB.Status(num)

请注意,如果str值在映射中不存在(注意区分大小写),映射查找将返回0。根据您如何定义您的协议缓冲区,0值可能会映射到一个没有“零”语义的枚举实例。因此,建议将0映射到一个“未知”实例:

  1. enum Status {
  2. UNKNOWN = 0;
  3. ENABLED = 1;
  4. // 其他值
  5. }

在Go中,如果字符串表示实际上是未知的,这将正确地产生一个临时的零值:

  1. v := testPB.Status(testPB.Status_value["does_not_exist"])
  2. fmt.Println(v == testPB.Status_UNKNOWN) // true

Go 1.18

使用泛型,可以编写可重用的代码来根据字符串值构造协议缓冲区枚举:

  1. func Enum[T ~string, PB ~int32](val T, pbmap map[string]int32, dft PB) PB {
  2. v, ok := pbmap[string(val)]
  3. if !ok {
  4. return dft
  5. }
  6. return PB(v)
  7. }

其中:

  • 类型参数T是字符串表示,也可以是具有基础类型为字符串的类型,例如type MyEnum string
  • 参数pbmap是生成的协议缓冲区代码中的<EnumName>_value
  • 类型参数PB是协议缓冲区枚举类型。

上述函数接受类型为PB的默认值,以便在字符串表示无效的情况下提供回退,并且还允许在PB上进行类型推断,否则PB将仅用作返回类型。

用法:

  1. type SomeEnum string
  2. const (
  3. SomeEnumFoo SomeEnum = "FOO"
  4. SomeEnumBar SomeEnum = "BAR"
  5. )
  6. func main() {
  7. foo := SomeEnumFoo
  8. v := Enum(foo, pb.SomeEnum_value, pb.SomeEnum_Foo)
  9. // ^ T ^ map[string]int32 ^ default PB value
  10. // v 的类型是 pb.SomeEnum
  11. }
英文:

The generated code has a map called &lt;EnumName&gt;_value of type map[string]int32. Then you can convert the numerical value to the actual defined type:

  1. num := testPB.Status_value[str]
  2. v := testPB.Status(num)

Consider that if the str value doesn't exist in the map (note that it's case sensitive), the map look-up will return 0. Depending on how you defined your protobuffer, the 0 value might be mapped to a an enum instance that does not have "zero" semantics. This is why it is recommended to map 0 to an "unknown" instance:

  1. enum Status {
  2. UNKNOWN = 0;
  3. ENABLED = 1;
  4. // and so on
  5. }

Which in Go correctly yields a makeshift zero-value if the string representation is effectively unknown:

  1. v := testPB.Status(testPB.Status_value[&quot;does_not_exist&quot;])
  2. fmt.Println(v == testPB.Status_UNKNOWN) // true

Go 1.18

With generics, it is possible to write reusable code to construct protobuffer enums from string values:

  1. func Enum[T ~string, PB ~int32](val T, pbmap map[string]int32, dft PB) PB {
  2. v, ok := pbmap[string(val)]
  3. if !ok {
  4. return dft
  5. }
  6. return PB(v)
  7. }

where:

  • the type parameter T is the string representation, which could also be a type with underlying type string, e.g. type MyEnum string
  • the argument pbmap is the &lt;EnumName&gt;_value from the generated protobuffer code
  • the type parameter PB is the protobuffer enum type.

The function above takes a default value of type PB to (obviously) have a fallback in case the string representation is invalid, and also to allow type inference on PB, which otherwise would be used only as a return type.

Usage:

  1. type SomeEnum string
  2. const (
  3. SomeEnumFoo SomeEnum = &quot;FOO&quot;
  4. SomeEnumBar SomeEnum = &quot;BAR&quot;
  5. )
  6. func main() {
  7. foo := SomeEnumFoo
  8. v := Enum(foo, pb.SomeEnum_value, pb.SomeEnum_Foo)
  9. // ^ T ^ map[string]int32 ^ default PB value
  10. // v is type pb.SomeEnum
  11. }

huangapple
  • 本文由 发表于 2021年8月4日 04:27:35
  • 转载请务必保留本文链接:https://go.coder-hub.com/68642422.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定