go: 在proto中使用oneof类型 在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的结构更紧凑,满足更多元化的需求。 来自 大脸猪 写于 2023-10-11 19:09 -- 更新于2023-10-11 19:48 -- 0 条评论