如何在proto3中用上golang对应的interface{}类型
作者:张富春(ahfuzhang),转载时请注明作者和引用链接,谢谢!
首先,我希望所有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.
如何在proto3中用上golang对应的interface{}类型的更多相关文章
- 如何在Drupal7中用代码批量创建节点、评论和分类
最近,我忙于一个网站迁移工作.网站是使用某个老式CMS建立的,有一定数量的文章.不同的分类数据和用户评论.我的团队被雇来把这些数据从这个浪费人力物力的老式CMS上完整的迁移到功能更现代的开源Drupa ...
- 如何在vscode中用standard style 风格去验证 vue文件
1 JavaScript Standard Style简介 本工具通过以下三种方式为你(及你的团队)节省大量时间: 无须配置. 史上最便捷的统一代码风格的方式,轻松拥有. 自动代码格式化. 只需运行 ...
- [译]How to Install Node.js on Ubuntu 14.04 如何在ubuntu14.04上安装node.js
原文链接为 http://www.hostingadvice.com/how-to/install-nodejs-ubuntu-14-04/ 由作者Jacob Nicholson 发表于October ...
- 如何在iOS地图上高效的显示大量数据
2016-01-13 / 23:02:13 刚才在微信上看到这篇由cocoachina翻译小组成员翻译的文章,觉得还是挺值得参考的,因此转载至此,原文请移步:http://robots.thought ...
- CentOS6.5上golang环境配置
CentOS6.5上golang环境配置 一.下载和解压go环境包 >>cd /usr/local/src/ >>wget -c http://golangtc.com/sta ...
- GPT分区基础知识及如何在GPT分区上安装WIN7
大硬盘和WIN8系统,让我们从传统的BIOS+MBR模式升级到UEFI+GPT模式,现在购买的主流电脑,都是预装WIN8系统,为了更好的支持2TB硬盘,更快速的启动win8,预装系统都采取了GPT分区 ...
- 如何在Windows系统上用抓包软件Wireshark截获iPhone等网络通讯数据
http://www.jb51.net/os/windows/189090.html 今天给大家介绍一种如何在Windows操作系统上使用著名的抓包工具软件Wireshark来截获iPhone.iPa ...
- 如何在Ubuntu Unity上修改应用程序图标
转自如何在Ubuntu Unity上修改应用程序图标 这篇文章将教大家在Ubuntu Unity上修改应用程序图标,这个教程适合于Ubuntu 14.04, Ubuntu 13.10, Ubuntu ...
- 如何在CentOS 7上修改主机名
如何在CentOS 7上修改主机名 在CentOS中,有三种定义的主机名:静态的(static),瞬态的(transient),和灵活的(pretty).“静态”主机名也称为内核主机名,是系统在启动时 ...
- 如何在 Android 手机上实现抓包?
如何在 Android 手机上实现抓包? http://www.zhihu.com/question/20467503 我想知道某个应用究竟在数据提交到哪里,提交了什么.网上的教程太复杂,不想麻烦.有 ...
随机推荐
- 万字讲解WiFi为何物
摘要:WiFi是一种基于IEEE802.11系列协议标准实现的无线通信技术. 本文分享自华为云社区<[云驻共创]物联网无线短距离Wi-Fi技术专题>,作者:Mr红凯. 前言 Wi-Fi通往 ...
- 火山引擎数智平台旗下DataWind升级半年报 6大功能助力企业数据消费
更多技术交流.求职机会,欢迎关注字节跳动数据平台微信公众号,回复[1]进入官方交流群 "以数据消费促数据生产"--是火山引擎提出的数据飞轮的核心理念,在这一理念的指导下,智能数 ...
- Solon 的多配置文件切换
比如有配置文件: app.yml app-dev.yml app-pro.yml 可以通过启动参数:-env java -jar demoapp.jar -env=dev
- web应用模式 api接口 接口测试工具postman restful规范
目录 web应用模式 前后端混合开发 流程说明(重要) 前后端分离开发 流程说明(重要) api接口 接口测试工具postman 基本介绍 编码格式 restful规范(重要) 简介 主要内容 练习 ...
- 极限五分钟,在宝塔中用 Docker 部署升讯威在线客服系统
我在业余时间开发维护了一款免费开源的升讯威在线客服系统,也收获了许多用户.对我来说,只要能获得用户的认可,就是我最大的动力. 最近客服系统成功经受住了客户现场组织的压力测试,获得了客户的认可. 客户组 ...
- 【辅助工具】Maven使用
Maven使用 错误排查 查看对应依赖在仓库中的路径,jar文件有没有下载成功,如果不成功直接把外部文件夹删除重新加载 导包错误 找到对应的路径,丛正常导入的同事直接复制过来. Maven启动项目 导 ...
- 【JAVA基础】报错解决
报错解决 Failed to configure a DataSource: 'url' attribute is not specified and no embedd https://change ...
- kafka如何保证数据的消息不丢失(最简洁)
一.kafka 本身配置层面1.1.replication.factor 默认值1创建kafka的topic时候,每个分区设置的副本数, 根据broker数量酌情设置, 建议业界通常做法设置为3 1. ...
- CompletableFuture 使用详解
CompletableFuture 使用详解 1. runAsync 和 supplyAsync方法 CompletableFuture 提供了四个静态方法来创建一个异步操作. public stat ...
- element-ui实现部分引用
1.首先安装 babel-plugin-component组件: 2.修改babel.js配置 1 module.exports = { 2 presets: [ 3 '@vue/app', 4 [' ...
