博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
gogoprotobuf使用(下)
阅读量:6282 次
发布时间:2019-06-22

本文共 10477 字,大约阅读时间需要 34 分钟。

hot3.png

声明:版权所有,谢绝转载。

   

承接上文,继续说明gogoprotobuf的各个option。

9 gogoproto.testgen & gogoproto.testgen_all

 testgen选项为true,则gogo会为相应的message生成一个测试用例与性能测试用例。testgen_all则为相应的package level的option。

pb code:option (gogoproto.testgen_all) = true;option (gogoproto.benchgen_all) = true;message A {	string msg = 1;}go code:package testimport testing "testing"import math_rand "math/rand"import time "time"import github_com_gogo_protobuf_proto "github.com/gogo/protobuf/proto"import encoding_json "encoding/json"func TestAProto(t *testing.T) {	popr := math_rand.New(math_rand.NewSource(time.Now().UnixNano()))	p := NewPopulatedA(popr, false)	data, err := github_com_gogo_protobuf_proto.Marshal(p)	if err != nil {		panic(err)	}	msg := &A{}	if err := github_com_gogo_protobuf_proto.Unmarshal(data, msg); err != nil {		panic(err)	}	for i := range data {		data[i] = byte(popr.Intn(256))	}	if !p.Equal(msg) {		t.Fatalf("%#v !Proto %#v", msg, p)	}}func BenchmarkAProtoMarshal(b *testing.B) {	popr := math_rand.New(math_rand.NewSource(616))	total := 0	pops := make([]*A, 10000)	for i := 0; i < 10000; i++ {		pops[i] = NewPopulatedA(popr, false)	}	b.ResetTimer()	for i := 0; i < b.N; i++ {		data, err := github_com_gogo_protobuf_proto.Marshal(pops[i%10000])		if err != nil {			panic(err)		}		total += len(data)	}	b.SetBytes(int64(total / b.N))}func BenchmarkAProtoUnmarshal(b *testing.B) {	popr := math_rand.New(math_rand.NewSource(616))	total := 0	datas := make([][]byte, 10000)	for i := 0; i < 10000; i++ {		data, err := github_com_gogo_protobuf_proto.Marshal(NewPopulatedA(popr, false))		if err != nil {			panic(err)		}		datas[i] = data	}	msg := &A{}	b.ResetTimer()	for i := 0; i < b.N; i++ {		total += len(datas[i%10000])		if err := github_com_gogo_protobuf_proto.Unmarshal(datas[i%10000], msg); err != nil {			panic(err)		}	}	b.SetBytes(int64(total / b.N))}func TestAJSON(t *testing.T) {	popr := math_rand.New(math_rand.NewSource(time.Now().UnixNano()))	p := NewPopulatedA(popr, true)	jsondata, err := encoding_json.Marshal(p)	if err != nil {		panic(err)	}	msg := &A{}	err = encoding_json.Unmarshal(jsondata, msg)	if err != nil {		panic(err)	}	if !p.Equal(msg) {		t.Fatalf("%#v !Json Equal %#v", msg, p)	}}func TestAProtoText(t *testing.T) {	popr := math_rand.New(math_rand.NewSource(time.Now().UnixNano()))	p := NewPopulatedA(popr, true)	data := github_com_gogo_protobuf_proto.MarshalTextString(p)	msg := &A{}	if err := github_com_gogo_protobuf_proto.UnmarshalText(data, msg); err != nil {		panic(err)	}	if !p.Equal(msg) {		t.Fatalf("%#v !Proto %#v", msg, p)	}}func TestAProtoCompactText(t *testing.T) {	popr := math_rand.New(math_rand.NewSource(time.Now().UnixNano()))	p := NewPopulatedA(popr, true)	data := github_com_gogo_protobuf_proto.CompactTextString(p)	msg := &A{}	if err := github_com_gogo_protobuf_proto.UnmarshalText(data, msg); err != nil {		panic(err)	}	if !p.Equal(msg) {		t.Fatalf("%#v !Proto %#v", msg, p)	}}

10 gogoproto.marshaler & gogoproto.sizer  gogoproto.marshaler_all & gogoproto.sizer_all

   sizer选项为true的时候,gogo会为相应的message生成method:"func Size() int";当marshaler为true的时候,gogo会为相应的method生成method:func Marshal()([] byte, int),这个method会调用Size(),所以marshaler为true的时候,sizer也必须为true。

pb code:option (gogoproto.marshaler_all) = true;option (gogoproto.sizer_all) = true;message A {	string msg = 1;}go gode:type A struct {	Msg              *string `protobuf:"bytes,1,opt,name=msg" json:"msg,omitempty"`	XXX_unrecognized []byte  `json:"-"`}func (m *A) Size() (n int) {	var l int	_ = l	if m.Msg != nil {		l = len(*m.Msg)		n += 1 + l + sovTest(uint64(l))	}	if m.XXX_unrecognized != nil {		n += len(m.XXX_unrecognized)	}	return n}func sovTest(x uint64) (n int) {	for {		n++		x >>= 7		if x == 0 {			break		}	}	return n}func sozTest(x uint64) (n int) {	return sovTest(uint64((x << 1) ^ uint64((int64(x) >> 63))))}func (m *A) Marshal() (data []byte, err error) {	size := m.Size()	data = make([]byte, size)	n, err := m.MarshalTo(data)	if err != nil {		return nil, err	}	return data[:n], nil}func (m *A) MarshalTo(data []byte) (n int, err error) {	var i int	_ = i	var l int	_ = l	if m.Msg != nil {		data[i] = 0xa		i++		i = encodeVarintTest(data, i, uint64(len(*m.Msg)))		i += copy(data[i:], *m.Msg)	}	if m.XXX_unrecognized != nil {		i += copy(data[i:], m.XXX_unrecognized)	}	return i, nil}func encodeFixed64Test(data []byte, offset int, v uint64) int {	data[offset] = uint8(v)	data[offset+1] = uint8(v >> 8)	data[offset+2] = uint8(v >> 16)	data[offset+3] = uint8(v >> 24)	data[offset+4] = uint8(v >> 32)	data[offset+5] = uint8(v >> 40)	data[offset+6] = uint8(v >> 48)	data[offset+7] = uint8(v >> 56)	return offset + 8}func encodeFixed32Test(data []byte, offset int, v uint32) int {	data[offset] = uint8(v)	data[offset+1] = uint8(v >> 8)	data[offset+2] = uint8(v >> 16)	data[offset+3] = uint8(v >> 24)	return offset + 4}func encodeVarintTest(data []byte, offset int, v uint64) int {	for v >= 1<<7 {		data[offset] = uint8(v&0x7f | 0x80)		v >>= 7		offset++	}	data[offset] = uint8(v)	return offset + 1}

新的marshal函数要比goprotobuf的proto.Marshal()函数效率高,因为它没用用reflect接口。

11 gogoprotobuf.unmarshaler & gogoprotobuf.unmarshaler_all

     当unmarshaler为true的时候,gogo会为相应的message生成method:func Unmarshal(data []byte) error,用以代替goprotobuf的proto.Unmarshal([]byte, *struct)函数。

pb code:option (gogoproto.unmarshaler_all) = true;message A {	string msg = 1;}go code:type A struct {	Msg              *string `protobuf:"bytes,1,opt,name=msg" json:"msg,omitempty"`	XXX_unrecognized []byte  `json:"-"`}func (m *A) Unmarshal(data []byte) error {	l := len(data)	index := 0	for index < l {		var wire uint64		for shift := uint(0); ; shift += 7 {			if index >= l {				return io.ErrUnexpectedEOF			}			b := data[index]			index++			wire |= (uint64(b) & 0x7F) << shift			if b < 0x80 {				break			}		}		fieldNum := int32(wire >> 3)		wireType := int(wire & 0x7)		switch fieldNum {		case 1:			if wireType != 2 {				return fmt.Errorf("proto: wrong wireType = %d for field Msg", wireType)			}			var stringLen uint64			for shift := uint(0); ; shift += 7 {				if index >= l {					return io.ErrUnexpectedEOF				}				b := data[index]				index++				stringLen |= (uint64(b) & 0x7F) << shift				if b < 0x80 {					break				}			}			postIndex := index + int(stringLen)			if postIndex > l {				return io.ErrUnexpectedEOF			}			s := string(data[index:postIndex])			m.Msg = &s			index = postIndex		default:			var sizeOfWire int			for {				sizeOfWire++				wire >>= 7				if wire == 0 {					break				}			}			index -= sizeOfWire			skippy, err := github_com_gogo_protobuf_proto.Skip(data[index:])			if err != nil {				return err			}			if (index + skippy) > l {				return io.ErrUnexpectedEOF			}			m.XXX_unrecognized = append(m.XXX_unrecognized, data[index:index+skippy]...)			index += skippy		}	}	return nil}

gogo官方关于这个函数有如下说明:

Remember when using this code to call proto.Unmarshal. This will call m.Reset and invoke the generated Unmarshal method for you. If you call m.Unmarshal without m.Reset you could be merging protocol buffers.

             from:  

其意思很明显,就是m (*A)调用m.Unmarshal方法之前,请先调用m.Reset()函数对其内容进行清空。否则,如果m连续调用了两次Unmarshal函数,则第二次反序列化出来的内容会被合并到第一次反序列化后的内容之后。

不过,一般情况下,很少会有人连续两次调用m.Unmarshal()方法吧?

12 equal & equal_all & verbose_equal & verbose_equal_all

如果设定了equal,则gogo为每个message生成一个Equal method。若设定了verbose_equal,则生成VerboseEqual method。Equal与VerboseEqual之间的差别在于,如果两个对象不等则VerboseEqual返回error不为nil,这个error会详细说明两个对象差别在哪里,便于debugging。

如果设定了testgen & testgen_all,则gogo会为这些equal函数生成测试函数。

pb code:  option (gogoproto.equal_all) = true;  option (gogoproto.verbose_equal_all) = true;  message B {	optional A A = 1 [(gogoproto.nullable) = false, (gogoproto.embed) = true];	repeated bytes G = 2 [(gogoproto.customtype) = "github.com/gogo/protobuf/test/custom.Uint128", (gogoproto.nullable) = false];  }  go code:func (this *B) VerboseEqual(that interface{}) error {	if that == nil {		if this == nil {			return nil		}		return fmt2.Errorf("that == nil && this != nil")	}	that1, ok := that.(*B)	if !ok {		return fmt2.Errorf("that is not of type *B")	}	if that1 == nil {		if this == nil {			return nil		}		return fmt2.Errorf("that is type *B but is nil && this != nil")	} else if this == nil {		return fmt2.Errorf("that is type *B but is not nil && this == nil")	}	if !this.A.Equal(&that1.A) {		return fmt2.Errorf("A this(%v) Not Equal that(%v)", this.A, that1.A)	}	if len(this.G) != len(that1.G) {		return fmt2.Errorf("G this(%v) Not Equal that(%v)", len(this.G), len(that1.G))	}	for i := range this.G {		if !this.G[i].Equal(that1.G[i]) {			return fmt2.Errorf("G this[%v](%v) Not Equal that[%v](%v)", i, this.G[i], i, that1.G[i])		}	}	if !bytes.Equal(this.XXX_unrecognized, that1.XXX_unrecognized) {		return fmt2.Errorf("XXX_unrecognized this(%v) Not Equal that(%v)", this.XXX_unrecognized, that1.XXX_unrecognized)	}	return nil}func (this *B) Equal(that interface{}) bool {	if that == nil {		if this == nil {			return true		}		return false	}	that1, ok := that.(*B)	if !ok {		return false	}	if that1 == nil {		if this == nil {			return true		}		return false	} else if this == nil {		return false	}	if !this.A.Equal(&that1.A) {		return false	}	if len(this.G) != len(that1.G) {		return false	}	for i := range this.G {		if !this.G[i].Equal(that1.G[i]) {			return false		}	}	if !bytes.Equal(this.XXX_unrecognized, that1.XXX_unrecognized) {		return false	}	return true}

13 总结

最后给出一个个人的gogoprotobuf文件样例:

syntax = "proto3";package test;option (gogoproto.gostring_all) = true;option (gogoproto.equal_all) = true;option (gogoproto.verbose_equal_all) = true;// option (gogoproto.goproto_stringer_all) = false;// option (gogoproto.stringer_all) =  true;// option (gogoproto.populate_all) = true;// option (gogoproto.testgen_all) = true;// option (gogoproto.benchgen_all) = true;option (gogoproto.marshaler_all) = true;option (gogoproto.sizer_all) = true;option (gogoproto.unmarshaler_all) = true;option (gogoproto.goproto_getters_all) = false;import "github.com/gogo/protobuf/gogoproto/gogo.proto";enum E {    option (gogoproto.goproto_enum_prefix) = false;    EA = 0;    EB = 2;}message A {	string msg = 1[(gogoproto.nullable) = false];}

其编译命令为:

#!/bin/sh# proto.sh# descriptor.protogopath=$HOME/bin/go/src# gogo.protogogopath=${gopath}/github.com/gogo/protobuf/protobuf# Mcommon.proto等号后面的值,用于把test.proto中import "common.proto"生成为 import "protocol/common"protoc --proto_path=$gopath:$gogopath:./ --gogo_out=Mcommon.proto=protocol/common:./src/pb test.proto

-----------------------------------

            写此文档的时候,得原公司(写文档的时候还在公司)同事陶春华兄大力相助, 在此致谢!2016/02/28。                                                          

转载于:https://my.oschina.net/alexstocks/blog/387058

你可能感兴趣的文章
翻译 | 摆脱浏览器限制的JavaScript
查看>>
闲扯下午引爆乌云社区“盗窃”乌云币事件
查看>>
02@在类的头文件中尽量少引入其他头文件
查看>>
JAVA IO BIO NIO AIO
查看>>
input checkbox 复选框大小修改
查看>>
网吧维护工具
查看>>
BOOT.INI文件参数
查看>>
vmstat详解
查看>>
新年第一镖
查看>>
unbtu使用笔记
查看>>
OEA 中 WPF 树型表格虚拟化设计方案
查看>>
Android程序开发初级教程(一) 开始 Hello Android
查看>>
使用Gradle打RPM包
查看>>
“我意识到”的意义
查看>>
淘宝天猫上新辅助工具-新品填表
查看>>
再学 GDI+[43]: 文本输出 - 获取已安装的字体列表
查看>>
nginx反向代理
查看>>
操作系统真实的虚拟内存是什么样的(一)
查看>>
hadoop、hbase、zookeeper集群搭建
查看>>
python中一切皆对象------类的基础(五)
查看>>