首页IT科技protocol(如何在proto3中用上golang对应的interface{}类型)

protocol(如何在proto3中用上golang对应的interface{}类型)

时间2025-06-14 02:34:35分类IT科技浏览4845
导读:作者:张富春(ahfuzhang ,转载时请注明作者和引用链接,谢谢!...

作者:张富春(ahfuzhang)              ,转载时请注明作者和引用链接                     ,谢谢!

cnblogs博客 zhihu Github 公众号:一本正经的瞎扯

首先      ,我希望所有golang中用于http请求响应的结构       ,都使用proto3来定义              。

麻烦的是                     ,有的情况下某个字段的类型可能是动态的             ,对应的JSON类型可能是number/string/boolean/null中的其中一种                    。

一开始我尝试用proto.Any类型       ,就像这样:

import "google/protobuf/any.proto"; message MyRequest{ google.protobuf.Any user_input = 1; // 用户可能输入 number / string / boolean / null 中的其中一种 }

使用protoc生成代码后                     ,发现这玩意儿完全没办法做json的encode/decode       。

理想的办法是让生成golang代码中的 user_input 成为 interface{} 类型              。但如何才能让proto3生成golang的interface类型呢?

尝试后发现可以用下面的办法解决:

1.使用gogo proto的扩展语法

import "google/protobuf/descriptor.proto"; import "github.com/gogo/protobuf/gogoproto/gogo.proto"; message MyRequest{ bytes user_input = 1[(gogoproto.customtype) = "InterfaceType"]; // 使用一个叫做 InterfaceType 的自定义类型 }

注意:InterfaceType 直接写成 interface{} 是不行的                    。因为 interface{} 类型没有实现序列化的接口       。

执行protoc后生成了如下代码:

type MyRequest struct { UserInput []InterfaceType `protobuf:"bytes,4,rep,name=user_input,proto3,customtype=InterfaceType" json:"user_input,omitempty"` }

2. 编写 InterfaceType 类型对应的序列化代码

// interface_type.go // 放在xxx.pb.go的同一目录下 package proto import ( "encoding/json" "errors" ) type InterfaceType struct { Value interface{} } func (t InterfaceType) Marshal() ([]byte, error) { return nil, errors.New("not implement") } func (t *InterfaceType) MarshalTo(data []byte) (n int, err error) { return 0, errors.New("not implement") } func (t *InterfaceType) Unmarshal(data []byte) error { return errors.New("not implement") } func (t *InterfaceType) Size() int { return -1 } // 因为只做JSON的序列化             ,所以只实现这两个方法就行了 func (t InterfaceType) MarshalJSON() ([]byte, error) { return json.Marshal(t.Value) } func (t *InterfaceType) UnmarshalJSON(data []byte) error { return json.Unmarshal(data, &t.Value) }

3.测试一下

// my_request.pb_test.go package proto import ( "encoding/json" "testing" ) func Test_MyRequest(t *testing.T) { j := `{"user_input":123}` inst := &MyRequest{} err := json.Unmarshal([]byte(j), inst) if err != nil { t.Errorf("json decode error, err=%+v", err) return } t.Logf("%+v", MyRequest) str, err := json.Marshal(inst) if err != nil { t.Errorf("json encode error, err=%+v", err) return } t.Logf("json=%s", string(str)) }

序列化和反序列化的结果一致       。

具体细节请参考这个链接:https://github.com/gogo/protobuf/blob/master/custom_types.md

have fun. ?

创心域SEO版权声明:以上内容作者已申请原创保护,未经允许不得转载,侵权必究!授权事宜、对本内容有异议或投诉,敬请联系网站管理员,我们将尽快回复您,谢谢合作!

展开全文READ MORE
遂平在线(遂平论坛遂平在线号) 企业网站SEO优化编写思路(有效提升企业网站排名的关键)