zoukankan      html  css  js  c++  java
  • protobuf文档翻译-安装,数据格式及编码规范

    Install

    Download protobuf: https://github.com/protocolbuffers/protobuf/releases

    unzip protoc-3.8.0-linux-x86_64.zip 
    sudo cp -r include/* /usr/local/include/
    sudo cp bin/protoc /usr/local/bin/
    

    Download Go support for protobuf:

    go get -u github.com/golang/protobuf/protoc-gen-go
    

    Download faster and also more customizable Go support:

    go get github.com/gogo/protobuf/protoc-gen-gofast
    

    Proto2.0

    每个proto文件中可以定义一组message。为了防止依赖关系等泛滥,一般只在一个proto文件中定义一组相关联的message。

    定义一个message

    message SomeMessage {
        [required|optional] type fieldName = fieldNumber [default=10];
    }
    

    fieldNumber 从1开始。

    注释

    注释的语法和C++相同:

    /* 这是一段注释 */
    // 这也是一段注释
    

    保留字段(Reserved Fields)

    当一个字段被删除后,后续的用户可以重新使用这个字段数字或名字, 就导致proto迁移过程中可能造成一些潜藏的bug。可以通过保留声明他们,
    将来如果有用户重用了这些字段,就会报错:

    message Foo {
        reserved 2, 15, 9 to 11;
        reserved "foo", "bar";
    }
    

    数据类型

    proto 注释 Go Python C++ Java
    double *float64 float double double
    float *float32 float float float
    int32 编码长度是可变的,不能用于编码负数。如果要用于负数,应当使用sint32 *int32 int int32 int
    int64 类似int32,应当使用sint64编码负数 *int64 int/log int64 long
    uint32 变长编码 *uint32 int/long uint32 int
    uint64 变长编码 *uint64 int/long uint64 long
    sint32 变长编码 *int32 int int32 int
    sint64 变长编码 *int64 int/long int64 long
    fixed32 4字节,比uint32更适合编码超过2^28的数字 *uint32 int/long uint32 int
    fixed64 8字节,2^56 *uint64 int/long uint64 long
    sfixed32 4字节 *int32 int int32 int
    sfixed64 8字节 *int64 int/long int64 long
    bool *bool bool bool boolean
    string 必须是UTF-8编码或是7bit的ASCII *string unicode(Py2), str(Py3) string String
    bytes 可以包含任意byte序列 []byte bytes string ByteString

    注意: 当说到更适合,或应当使用时,并不是说这个类型的表达范围不能够比得上另一种类型,而是其编码长度更有效率。

    可选字段和默认值

    一个message中可以设定一个字段为optional,当消息解码时发现该字段缺席,就会按照默认值(default)给定值,否则给定该类型的默认值(类似Go),枚举类型则会使用第一个枚举值。

    形如:

    optional int32 result_per_page = 3 [default=10];
    

    枚举类型

    枚举类型使用的是32位整形数,如果使用了负数,编码效率会变低

    enum Corpus {
        UNIVERSAL = 0;
        WEB = 1;
        IMAGES = 2;
    }
    

    枚举类型中默认第二个值是不能重复的,如果要有重复,那么就要指定允许别名:

    enum State {
        option allow_alias = true;
        UNKNOWN = 0;
        STARTED = 1;
        RUNNING = 1;
    }
    

    保留枚举

    如果你删除了枚举中的一个值,那么以后别人就可以重新用它们。可以这样保留这些字段:

    enum Foo {
        reserved 2, 15, 9 to 11, 40 to max;
        reserved "FOO", "BAR";
    }
    

    导入定义

    import "myproject/other_proto.proto"
    import public "new.proto"
    

    要想让protoc找到它们,需要通过 -I 或 --proto_path 来定义,一般是将项目根目录作为 --proto_path 参数。

    类型嵌套

    message SearchResponse {
        message Result {
            required string url = 1;
            optional string title = 2;
            repeated string snippets = 3;
        }
        repeated Result result = 1;
    }
    
    message SomeOtherMessage {
        optional SearchResponse.Result result = 1; // 从外部引用一个嵌套类型
    }
    

    Proto3.0

    syntax = "proto3";
    
    message SearchRequest {
        string query = 1;
        int32 page_number = 2;
        int32 result_per_page = 3;
    }
    
    • singular: 0或1个该字段
    • repeated: 可以出现0到多个该字段

    proto3中数字类型默认使用packed编码

    类型更新

    • 不要更改任何现有字段的field number
    • 旧message的默认值应当保持不变
    • 字段可以移除,在该field number不再使用的前提下
    • int32/uint32/int64/uint64/bool 是兼容的,可以任意修改类型,但是可能会出现精度问题等
    • sint32与sint64 兼容,但不与其它类型兼容
    • string和bytes兼容,前提是它们都是有效的UTF-8编码
    • 如果bytes包含了编码的message,嵌套message与bytes兼容
    • fixed32 与 sfixed32/fixed64/sfixed64兼容
    • enum与 int32/uint32/int64/uint64兼容
    • 把单个字段放入一个新的oneof是安全且兼容的;把多个字段放入一个新的oneof 可能 是安全且兼容的,如果你确认没有代码同时设定这多个字段的前提下。 把任何字段放入一个现存的oneof是不安全兼容的。

    未知字段

    由于proto版本兼容问题,导致旧的废弃字段不能被使用,proto3开始时会直接丢弃它们,但从3.5开始将它们保留

    任意类型

    任意类型 Any 本质上就是序列化好的bytes类型, 使用该类型需要引入 google/protobuf/any.proto:

    import "google/protobuf/any.proto";
    
    message ErrorStatus {
        string message = 1;
        repeated google.protobuf.Any details = 2;
    }
    

    Oneof

    如果message中有若干字段,一次最多只会设置其中的一个字段,那么就可以通过oneof来约定这种关系,类似于C语言的union:

    message SampleMessage {
        oneof test_oneof {
            string name = 4;
            SubMessage sub_message = 9;
        }
    }
    

    oneof 的向后兼容

    如果检查一个oneof的值返回 None/NOT_SET, oneof可能没有设置值,也可能是版本不同,但我们无法断定这件事。

    Maps

    map<key_type, value_type> map_field = N;
    
    • map类型字段不可以是 repeated
    • 遍历顺序/传输序列化顺序是不可知的
    • 从map专程text格式时会对key做排序
    • 从传输数据传入或合并时,如果map中的key存在重复,使用最后一个,从text格式处理map时,如果key重复会导致失败
    • 如果只提供key但不提供值,那么序列化行为随语言而定

    Map类型在传输时等价于:

    message MapFieldEntry {
        key_type key = 1;
        value_type value = 2;
    }
    
    repeated MapFieldEntry map_field = N;
    

    Packages

    package foo.bar;
    message Open { ... }
    
    message Foo {
        foo.bar.Open open = 1;
    }
    

    在Go中这会被当成包名

    Services

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

    Options

    options不会修改数据定义,但是会影响一些语言生成的行为等等。

    optimize_for

    这是一个文件级选项,用于设定生成代码的优化方向。

    optimize_for [SPEED|CODE_SIZE|LITE_RUNTIME]
    

    SPEED: 默认值,优先生成高效编解码的代码
    CODE_SIZE: 利用反射等语言特性生成体积小的代码,但操作可能会更慢
    LITE_RUNTIME: 使用一个体积更小,也更少特性(如反射)的运行时来进行编解码

    deprecacted

    字段选项,用于暗示字段已弃用,新代码不应当再使用它。Java中会加入@Deprecated,其它语言暂不支持。

    自定义选项

    protobuf允许自定义选项,虽然大部分情况用不上: https://developers.google.com/protocol-buffers/docs/proto.html#extensions

    JSON

    protobuf 提供了JSON输出格式,部分类型可能与想象有所不同:

    proto3 JSON JSON Example Notes
    enum string "FOO_BAR" 默认使用枚举的名字,不过处理时使用int值也是可以的
    map<K,V> object {"k1":v1,...} 所有的key都会被转换成字符串
    repeated V array [v1, ...] null 会被解析城空的列表
    bytes base64 string "YWJjMT..." 编码时会自动使用带padding的标准Base64编码成字符串
    int32/fixed32/uint32 number 1, -10, 0 JSON值会是一个10进制数字,解析时数字或者字符串都可以接受
    int64/fixed64/uint64 string "1", "-10" 由于64位整数已经超出了JSON number的表示范围,编码解码都是用string
    float/double number 1.1, -10.0, "NaN", "Infinity","-Infinity" 编码时会被做成number或特殊字符串,解码时数字或字符串都可以
    Any object {"@type":"url", "f": v, ...} @type暗示了真实的数据类型,如果Any中包含了一个值是特定的原生JSON数据,则会直接被解析出来 {"@type": xxx, "value": yyy}
    Timestamp string "1972-01-01T10:00:20.021Z" RFC3339,尾部小数点后可以有0,3,6,9位数字
    Duration string "1.0002s", "1s" 尾部必须是s结尾,前面可以使用很多小数精度,但精度范围要在纳秒范围内
    struct object {...} see struct.proto
    包装类型(别名) 与实际对应的类型行为保持一致
    Empty object {} 空对象
    NullValue null JSON null

    在渲染JSON时,默认proto3不会输出值与默认值相等的字段,除非特别通过option指定

    使用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
    

    编码规范

    文件名使用蛇形:

    lower_snake_case.proto
    

    文件格式

    • 一行最长80字符
    • 2空格缩进

    文件结构

    1. License header
    2. File overview
    3. Syntax
    4. Package
    5. Imports (sorted)
    6. File options
    7. Everything else

    重复字段(数组)

    使用复数形式:

    repeated string keys = 1;
    repeated MyMessage accounts = 17;
    

    枚举

    枚举使用C语言的标准形式:全大写,下划线

    Service

    Service使用CamelCase

    需要避免的

    required和groups,这是给proto2用的,proto3不需要

  • 相关阅读:
    [hihocoder-1974] 智能分包 状态压缩dp
    2018北京ICPC D. Frog and Portal 斐波那契数 构造
    [hdu-6621]K-th Closest Distance 主席树 线段树 2019 多校4
    [POJ 2104]K-th Number 主席树 可持久化线段树 入门
    [hdu-6623]Minimal Power of Prime
    [hdu-6608] Fansblog 威尔逊定理 质数的密度分布 2019 多校 3
    [codeforces1000F] One Occurrence
    [python] 机器学习 卷积神经网络 用迁移学习实现人脸识别
    [python] 安装TensorFlow问题 解决Cannot uninstall 'wrapt'. It is a distutils installed project
    浅谈getResource方法
  • 原文地址:https://www.cnblogs.com/qianyuming/p/10955822.html
Copyright © 2011-2022 走看看