如何从字符串表示中获取 Protobuf 枚举值?

use*_*011 8 go protocol-buffers grpc-go

我可以使用以下指令获取 Protobuf 枚举的字符串值:

str := testPB.Status_ENABLED.String()
Run Code Online (Sandbox Code Playgroud)

如何进行逆运算?(从字符串中获取枚举元素)。

bla*_*een 10

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

num := testPB.Status_value[str]
v := testPB.Status(num)
Run Code Online (Sandbox Code Playgroud)

考虑一下,如果str映射中不存在该值(请注意,它区分大小写),则映射查找将返回0. 根据您定义原型缓冲区的方式,该0值可能会映射到不具有“零”语义的枚举实例。这就是为什么建议映射0到“未知”实例:

enum Status {
  UNKNOWN = 0;
  ENABLED = 1;
  // and so on
}
Run Code Online (Sandbox Code Playgroud)

如果字符串表示形式实际上未知,那么 Go 中会正确生成临时零值:

v := testPB.Status(testPB.Status_value["does_not_exist"]) 
fmt.Println(v == testPB.Status_UNKNOWN) // true
Run Code Online (Sandbox Code Playgroud)

去1.18

使用泛型,可以编写可重用的代码来从字符串值构造 protobuffer 枚举:

func Enum[T ~string, PB ~int32](val T, pbmap map[string]int32, dft PB) PB {
    v, ok := pbmap[string(val)]
    if !ok {
        return dft
    }
    return PB(v)
}
Run Code Online (Sandbox Code Playgroud)

在哪里:

  • 类型参数T是字符串表示形式,也可以是具有底层类型字符串的类型,例如type MyEnum string
  • 参数pbmap来自<EnumName>_value生成的 protobuffer 代码
  • 类型参数PB是 protobuffer 枚举类型。

上面的函数采用 type 的默认值PB(显然)在字符串表示形式无效时进行后备,并且还允许对 进行类型推断PB,否则该值将仅用作返回类型。

用法:

type SomeEnum string

const (
    SomeEnumFoo SomeEnum = "FOO"
    SomeEnumBar SomeEnum = "BAR"
) 

func main() {
    foo := SomeEnumFoo
    v := Enum(foo, pb.SomeEnum_value, pb.SomeEnum_Foo)
    //        ^ T  ^ map[string]int32 ^ default PB value
    // v is type pb.SomeEnum
}
Run Code Online (Sandbox Code Playgroud)