syntax = "proto3"; // 须在文件第一行指定,不指定默认为proto2
/*
proto file search by -I/--proto_path flag. 指定protobuf文件位置
*/
import "old.proto";
import public "new.proto"; // public 可以被导入到新的proto
import "google/protobuf/any.proto"; // 导入Any类型定义
package message; // 包名
option go_package = ".;package_name"/"./package_name" // package name 是生成文件的包名,前者在指定目录当前目录,后者在package_name文件加下
/*
Field Numbers:
- 必须唯一
- 一旦使用避免修改
- 1-15 1byte, 16-2047 2bytes 频繁使用的字段建议使用1-15编号,编号范围:1-2^29-1,保留范围:19000-19999
- reserved 用于保留字段
*/
message SearchRequest {
// string query = 1;
int32 page_number = 2;
int32 result_per_page = 3;
reserved 4, 7, 12 to 15;
reserved "query";
enum Corpus {
option allow_alias = true; // 允许别名
UNIVERSAL = 0;
WEB = 1;
PHONE = 1;
IMAGES = 2;
LOCAL = 3;
// NEWS = 4;
PRODUCTS = 5;
VIDEO = 6;
reserved "NEWS";
}
Corpus corpus = 5;
// 嵌套消息类型
message Result {
string url = 1;
string title = 2;
repeated string snippets = 3;
}
repeated Result result = 6;
}
// 复用嵌套类型
message OtherResponse {
SearchRequest.Result result = 1;
repeated google.protobuf.Any details = 2;
// OneOf 仅能出现其中一个字段,当出现其中一个字段时,其内容会被覆盖
// 可以加入除 map和repeated 以外的所有类型字段
oneof test_oneof {
string name = 4;
int32 score = 5;
}
// Map 兼容定义
message MapFieldEntry {
key_type key = 1;
value_type value = 2;
}
repeated MapFieldEntry map_field = 6;
message.message.SearchRequest open = 7;
}
/*
Scalar Value Type: 标量类型
- double
- float
- int32
- int64
- uint32
- uint64
- sint32 当包含负数时编码更有效,节省传输量(protocol buffer中为什么同时出现int32类型,uint32,sint32类型? - ncwo的回答 - 知乎
https://www.zhihu.com/question/57333235/answer/152501389) - sint64 同上
- fixed32 当值经常大于 2^28 时比uint32有效
- fixed64 2^56
- sfixed32
- sfixed64
- bool
- string 必须小于2^32
- bytes 小于2^32bytes
*/
/*
默认值:
- string -> ""
- bytes -> b""
- bool -> false
- numeric types -> 0
- enums -> first defined enum value, must be 0
- 其它类型 -> 语言特定默认值
*/
/*
Enum Type:
- 必须将定义映射到0的常量作为第一个元素(1. 必须有默认值;2. 为了兼容proto2)
- 可以使用别名定义相同的枚举值不同的常量
- 枚举范围32bit integer,负数是低效的,不推荐。
- 当更新枚举值时,为避免旧版本proto问题,建议保留已删除的数值;
*/
/*
更新Message Type
更新规则:
- 不要修改任何已存在字段的field number
- 当添加新的字段时,新的会使用字段默认值,旧的忽略新字段
- 当移除字段时,最好添加"OBSOLETE_"前缀标记为过期,或者保留field number, 避免后面复用field number
- int32,uint32,int64,uint64 and bool 是兼容的
- sint32 and sint64 兼容
- string and bytes 兼容
- fixed32,sfixed32, fixed64 and sfixed64 兼容
- 对于消息字段如 string, bytes,可选和重复是兼容的
- enum,int32,uint32,int64,uint64 兼容
- 将单个值更改为 oneof 成员是安全的,但是将任何字段移至现有字段都不安全
*/
/* Unknown Fields
=proto3.5 未知字段会被序列化输出
*/
/* Any
Any 可以使消息内嵌到.proto文件,前提是需要导入 google/protobuf/any.proto
*/
/* Oneof
- 最后一次设置的值会覆盖前面设置的值
- 如何遇到同一对象的多个成员则在解析消息中仅使用最后看到的成员
- oneof 不可以为 repeated
- 反射API可以工作与oneof
- 如果设置oneof field为默认值,值仍会被序列化
*/
/*
Maps
map<key_type, value_type> map_field = N;
map<string, Project> projects = 3;
- key_type 可以为任意数字或字符串类型,value_type 可以为除map以外类型
- Map不能为repeated
- map顺序不确定
- 文本键按照string排序,数字键按照数字排序
- 当解析时相同的键最后一个被使用,而从文本格式解析时,存在多个键时解析会失败
- 当包含一个没有值的map field时,依赖语言实现。
*/
/* Define Services
定义服务
*/
service SearchService {
rpc Search(SearchRequest) returns (OtherResponse);
}
/*
生成代码
提前下载protoc程序
protoc --proto_path=IMPORT_PATH --cpp_out=DST_DIR --java_out=DST_DIR --python_out=DST_DIR --go_out=DST_DIR --ruby_out=DST_DIR --objc_out=DST_DIR --csharp_out=DST_DIR path/to/file.proto
-I=IMPORT_PATH == --proto_path=IMPORT_PATH 用于指定 proto 文件位置,可以指定多个proto文件
*/