如何将oneof类型在proto中成?

摘要:在proto中,可以使用OneOf类型,使用一个字段存储不同类型的数据。类似go中的interface。 假设有proto如下,Val是一个OneOf数据类型,它可以为doubleintstr...中的任意一种。 TestPB中引用了v
在proto中,可以使用OneOf类型,使用一个字段存储不同类型的数据。类似go中的interface。 假设有proto如下,Val是一个OneOf数据类型,它可以为double/int/str...中的任意一种。 TestPB中引用了value,类型为Val。 syntax = "proto3"; package protooneof; option go_package = "pb/message"; message Val{ oneof oneof_val { double double = 1; int64 int = 2; string str = 3; bytes bytes = 4; uint64 uint = 5; float float = 6; } } message TestPB { Val value = 1; } 赋值 编译这个proto,可以使用以下的代码对Val类型赋值: msg := &message.TestPB{ Value: &message.Val{ OneofVal: &message.Val_Str{Str: "hello"}, // 对oneof赋值需要使用Val包装,然后内部指定具体的类型 }, } 同理,使用=赋值也是可以的: msg.Value = &message.Val{ OneofVal: &message.Val_Float{Float: 123}, } 取值 假设知道值的类型,可以直接调用GetXXX方法取值。 fv := msg.GetValue().GetStr() fmt.Printf("fv:%v\n", fv) // 输出 hello 但是如果这个值未设置或者不存在,则会返回这个类型的0值。 这就带来问题,如何判定这个值是否已设置,如果已设置是什么类型? 可以使用switch类型判定的方式来解决需求,因为已经穷举了Val所有可能的类型,如果未设置值,会打印未设置值。 switch v := msg.GetValue().GetOneofVal().(type) { case *message.Val_Int: fmt.Printf("int val:%v\n", v.Int) case *message.Val_Float: fmt.Printf("float val:%v\n", v.Float) case *message.Val_Double: fmt.Printf("double val:%v\n", v.Double) case *message.Val_Str: fmt.Printf("str val:%v\n", v.Str) case *message.Val_Bytes: fmt.Printf("bytes val:%v\n", v.Bytes) case *message.Val_Uint: fmt.Printf("uint val:%v\n", v.Uint) default: fmt.Printf("未设置值\n") } 通过善用Oneof类型,可以让pb的结构更紧凑,满足更多元化的需求。