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

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

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

问题

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

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

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

英文:

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

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。然后,您可以将数值转换为实际定义的类型:

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

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

enum Status {
  UNKNOWN = 0;
  ENABLED = 1;
  // 其他值
}

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

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

Go 1.18

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

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)
}

其中:

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

上述函数接受类型为PB的默认值,以便在字符串表示无效的情况下提供回退,并且还允许在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 的类型是 pb.SomeEnum
}
英文:

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:

num := testPB.Status_value[str]
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:

enum Status {
  UNKNOWN = 0;
  ENABLED = 1;
  // and so on
}

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

v := testPB.Status(testPB.Status_value[&quot;does_not_exist&quot;]) 
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:

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)
}

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:

type SomeEnum string

const (
	SomeEnumFoo SomeEnum = &quot;FOO&quot;
	SomeEnumBar SomeEnum = &quot;BAR&quot;
) 

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
}

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:

确定