英文:
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 <EnumName>_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["does_not_exist"])
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<EnumName>_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 = "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
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论