gRPC--Proto 语法

397 阅读6分钟

Protoc 语法

本文主要介绍了 Protocol Buffers(简称 proto)的基本数据类型、标量类型、结构定义及高级用法,并结合 Go 语言的实现进行说明。

  1. 基本数据类型

    定义了 Request 消息体,包含多种数据类型字段,如 doublefloatint32 等,并展示了其在 Go 中的映射关系。每种数据类型在不同编程语言中有对应的类型转换规则。

  2. 标量类型

    列举了 proto 标量类型的特性及适用场景。例如,int32uint32 使用变长编码,sint32 对负值更高效,fixed32fixed64 固定字节长度适合大数值等。未赋值字段在序列化时会被赋予默认值。

  3. 结构定义

    • message 定义:消息体以大写字母开头,字段名以下划线命名并分配唯一标识。
    • 切片(数组):使用 repeated 关键字表示数组类型。
    • map:支持键值对形式的数据结构。
    • 嵌套类型:允许在一个 message 内部定义子 message。
    • 字段作废:通过 reserved 保留字段编号或名称,避免冲突。
    • 枚举类型:必须包含值为 0 的枚举常量,支持别名设置。
  4. oneof

    在一个 oneof 块中,多个字段共享同一存储空间,设置其中一个字段会清空其他字段。

  5. 服务定义

    提供四种服务定义方式:

    • 即刻响应服务。
    • 入参为流的服务。
    • 出参为流的服务。
    • 入参和出参均为流的服务。

基本数据类型

message Request {
  double a1 = 1;
  float a2 = 2;
  int32 a3 = 3;
  uint32 a4 = 4;
  uint64 a5 = 5;
  sint32 a6 = 6;
  sint64 a7 = 7;
  fixed32 a8 = 8;
  fixed64 a9 = 9;
  sfixed32 a10 = 10;
  sfixed64 a11 = 11;
  bool a12 = 12;
  string a13 = 13;
  bytes a14 = 14;
}
type Request struct {
  state         protoimpl.MessageState
  sizeCache     protoimpl.SizeCache
  unknownFields protoimpl.UnknownFields

  A1  float64 `protobuf:"fixed64,1,opt,name=a1,proto3" json:"a1,omitempty"`
  A2  float32 `protobuf:"fixed32,2,opt,name=a2,proto3" json:"a2,omitempty"`
  A3  int32   `protobuf:"varint,3,opt,name=a3,proto3" json:"a3,omitempty"`
  A4  uint32  `protobuf:"varint,4,opt,name=a4,proto3" json:"a4,omitempty"`
  A5  uint64  `protobuf:"varint,5,opt,name=a5,proto3" json:"a5,omitempty"`
  A6  int32   `protobuf:"zigzag32,6,opt,name=a6,proto3" json:"a6,omitempty"`
  A7  int64   `protobuf:"zigzag64,7,opt,name=a7,proto3" json:"a7,omitempty"`
  A8  uint32  `protobuf:"fixed32,8,opt,name=a8,proto3" json:"a8,omitempty"`
  A9  uint64  `protobuf:"fixed64,9,opt,name=a9,proto3" json:"a9,omitempty"`
  A10 int32   `protobuf:"fixed32,10,opt,name=a10,proto3" json:"a10,omitempty"`
  A11 int64   `protobuf:"fixed64,11,opt,name=a11,proto3" json:"a11,omitempty"`
  A12 bool    `protobuf:"varint,12,opt,name=a12,proto3" json:"a12,omitempty"`
  A13 string  `protobuf:"bytes,13,opt,name=a13,proto3" json:"a13,omitempty"`
  A14 []byte  `protobuf:"bytes,14,opt,name=a14,proto3" json:"a14,omitempty"
 }

proto 各语言类型转换

Proto TypeC++ TypeJava/Kotlin Type\[1]Python Type\[3]Go TypeRuby TypeC# TypePHP TypeDart TypeRust Type
doubledoubledoublefloatfloat64Floatdoublefloatdoublef64
floatfloatfloatfloatfloat32Floatfloatfloatdoublef32
int32int32\_tintintint32Fixnum or Bignum (as required)intintegerinti32
int64int64\_tlongint/long\[4]int64Bignumlonginteger/string\[6]Int64i64
uint32uint32\_tint\[2]int/long\[4]uint32Fixnum or Bignum (as required)uintintegerintu32
uint64uint64\_tlong\[2]int/long\[4]uint64Bignumulonginteger/string\[6]Int64u64
sint32int32\_tintintint32Fixnum or Bignum (as required)intintegerinti32
sint64int64\_tlongint/long\[4]int64Bignumlonginteger/string\[6]Int64i64
fixed32uint32\_tint\[2]int/long\[4]uint32Fixnum or Bignum (as required)uintintegerintu32
fixed64uint64\_tlong\[2]int/long\[4]uint64Bignumulonginteger/string\[6]Int64u64
sfixed32int32\_tintintint32Fixnum or Bignum (as required)intintegerinti32
sfixed64int64\_tlongint/long\[4]int64Bignumlonginteger/string\[6]Int64i64
boolboolbooleanboolboolTrueClass/FalseClassboolbooleanboolbool
stringstd::stringStringstr/unicode\[5]stringString (UTF-8)stringstringStringProtoString
bytesstd::stringByteStringstr (Python 2), bytes (Python 3)\[]byteString (ASCII-8BIT)ByteStringstringListProtoBytes

标量类型

.proto Type解释Go Type
doublefloat64
floatfloat32
int32使用变长编码,对于负值的效率很低,如果你的域有可能有负值,请使用sint64替代int32
uint32使用变长编码uint32
uint64使用变长编码uint64
sint32使用变长编码,这些编码在负值时比int32高效的多int32
sint64使用变长编码,有符号的整型值。编码时比通常的int64高效int64
fixed32总是4个字节,如果数值总是比总是比228大的话,这个类型会比uint32高效。uint32
fixed64总是8个字节,如果数值总是比总是比256大的话,这个类型会比uint64高效。uint64
sfixed32总是4个字节int32
sfixed64总是8个字节int64
boolbool
string一个字符串必须是UTF-8编码或者7-bit ASCII编码的文本string
bytes可能包含任意顺序的字节数据\[]byte

当标量类型没有被赋值时,是不会被序列化的,解析时就会赋予默认值。 strings:空字符串,bytes:空序列,bools:false,数值类型:0

message 定义结构

message 名称(大写开头) { 类型 key(下划线) = 唯一(标识) }


message Req{  
string user_name = 1;  
}

切片(数组)

message ArrayRequest {
  repeated int64 a1 = 1;
  repeated string a2 = 2;
  repeated Request request_list = 3;
}

ps:需要添加关键字 repeated

type ArrayRequest struct {
  A1          []int64 
  A2          []string   
  RequestList []*Request
}

map

map<key 类型,value 类型> key = 标识;

message MapRequest {
  map<int64, string> m_i_s = 1;
  map<string, bool> m_i_b = 2;
  map<string, ArrayRequest> m_i_arr = 3;
}
type MapRequest struct {

  MIS   map[int64]string
  MIB   map[string]bool
  MIArr map[string]*ArrayRequest
}

类型嵌套

message Req{
 message Person{
  string name = 1;
 }
int32 id  = 1;
Person person = 2;
}

字段作废

通过reserved 实现字段作废(保留)

message Req{
 string user_name = 1;
 string one = 2;
 string two = 3;
 string three = 4;
 string four = 5;
 string five = 6;
 reserved 2,4 to 6;
 reserved "one","five";
}

枚举类型

一定要存在一个枚举常量值为 0,不然不合法。

message SearchRequest {
string query = 1;
int32 page_number = 2;
int32 result_per_page = 3;
enum Corpus {
UNIVERSAL = 0;
WEB = 1;
IMAGES = 2;
LOCAL = 3;
NEWS = 4;
PRODUCTS = 5;
VIDEO = 6;
}
Corpus corpus = 4;
}

ps:当你的枚举里面存在相同常量值的时候 必须设置这个选项

options allow_alias = true;

oneof

我们可以再message里用 oneof 来包裹某个段落。在这个作用区域中,所有的值只要被设置过了,其他的值会被清空

message Response {
  oneof response_type {
    User user = 1;
    Error error = 2;
    EmptyResponse empty = 3;
  }
}

四种定义服务

1.传统的 即刻响应的

service SearchService {
rpc Search(SearchRequest) returns (SearchResponse);
}


2.入参为流

rpc SearchIN(stream PersonReq) returns (PersonRes);

3.出参为流

rpc SearchOUT(PersonReq) returns (stream PersonRes);

4.入参、出参皆为流

rpc SearchIO(stream PersonReq) returns (stream PersonRes);