🔥个人主页:Milestone-里程碑

❄️个人专栏: <<力扣hot100>> <<C++>><<Linux>>

       <<Git>><<MySQL>>

🌟心向往之行必能至

目录

一、版本兼容的核心目标

二、3 个核心规则(小白记死,不会错)

规则 1:字段编号一旦确定,绝对不能改

规则 2:新增字段,用新的编号(别复用旧编号)

规则 3:删除字段,要保留编号(别复用)

三、字段类型能随便改吗?(小白常用兼容类型)

四、实战:模拟版本升级

1. 旧版本 .proto(V1)

2. 新版本 .proto(V2):新增地址、微信,删除年龄

3. 兼容性测试效果

五、总结:版本兼容的关键


实际项目中,需求会变:比如一开始通讯录只有姓名、电话,后来要加地址、微信字段。如果直接修改 .proto 文件,旧程序(没升级的)可能会解析失败 —— 但 Protobuf 天生支持版本兼容,只要遵循几个简单规则,新老程序就能和平共处。

这篇用大白话讲清楚版本兼容的核心规则,小白也能轻松掌握。

一、版本兼容的核心目标

  • 新程序能解析旧程序打包的数据(比如新程序加了地址字段,能解析旧程序没地址的通讯录);
  • 旧程序能解析新程序打包的数据(比如旧程序没地址字段,能正常解析新程序有地址的通讯录,只是看不到地址);
  • 不用改旧程序的代码,直接用就行。

二、3 个核心规则(小白记死,不会错)

规则 1:字段编号一旦确定,绝对不能改

每个字段的编号(比如 name = 1age = 2)是 Protobuf 识别字段的唯一标识,改了编号,旧程序就认不出这个字段了。

错误示例

  • 旧 .proto:string name = 1;
  • 新 .proto:string name = 8;(把编号从 1 改成 8)
  • 后果:旧程序解析新程序的数据时,会找不到姓名字段;新程序解析旧程序的数据时,也认不出姓名。
规则 2:新增字段,用新的编号(别复用旧编号)

想加新字段(比如地址、微信),直接用没被用过的编号就行,不用改旧字段。

正确示例

  • 旧 .proto:string name = 1; int32 age = 2;
  • 新 .proto:string name = 1; int32 age = 2; string address = 3;(新增地址字段,用编号 3)

效果

  • 旧程序解析新数据:能正常读取姓名、年龄,地址字段会被当作 “未知字段” 忽略,不影响使用;
  • 新程序解析旧数据:地址字段会用默认值(字符串默认空,数字默认 0)。
规则 3:删除字段,要保留编号(别复用)

如果某个字段不用了(比如删除 “年龄” 字段),不能直接删掉后把编号给新字段用 —— 否则新字段会和旧程序的旧字段冲突。

正确做法:用 reserved 关键字保留被删除字段的编号,禁止复用。

示例

  • 旧 .proto:string name = 1; int32 age = 2;
  • 新 .proto:

    proto

    syntax = "proto3";
    package contacts;
    
    message PeopleInfo {
      reserved 2; // 保留编号 2(原来的年龄字段),禁止复用
      string name = 1;
      string address = 3; // 新增地址字段,用新编号 3
    }
    

效果:后续有人想把新字段的编号设为 2,编译时会报错,避免冲突。

三、字段类型能随便改吗?(小白常用兼容类型)

不是所有类型都能随便改,但以下常用类型可以互相改,不影响兼容:

  • 整数类型:int32uint32int64bool(比如把 int32 age 改成 bool is_adult);
  • 字符串和字节:stringbytes(只要字节是合法的 UTF-8 编码);
  • 枚举和整数:enum 类型可以和 int32uint32 互相改。

不兼容的修改:把 string name 改成 int32 name(文字改成数字),旧程序解析会出错。

四、实战:模拟版本升级

1. 旧版本 .proto(V1)

proto

syntax = "proto3";
package contacts;

message PeopleInfo {
  string name = 1;          // 姓名
  int32 age = 2;           // 年龄
  repeated string phone = 3; // 多个电话
}
2. 新版本 .proto(V2):新增地址、微信,删除年龄

proto

syntax = "proto3";
package contacts;

message PeopleInfo {
  reserved 2; // 保留年龄字段的编号 2
  string name = 1;          // 姓名
  repeated string phone = 3; // 多个电话
  string address = 4;       // 新增地址(新编号 4)
  string weixin = 5;        // 新增微信(新编号 5)
}
3. 兼容性测试效果
  • 旧程序解析 V2 数据:能正常读取姓名、电话,地址和微信被忽略;
  • 新程序解析 V1 数据:姓名、电话正常读取,地址和微信为空字符串(默认值);
  • 完全不用改旧程序代码,直接能用。

五、总结:版本兼容的关键

  1. 字段编号是核心,不改、不复用删除字段的编号;
  2. 新增字段用新编号;
  3. 删除字段用 reserved 保留编号;
  4. 类型修改只在兼容类型之间改。

遵循这几点,你的 Protobuf 协议能在项目迭代中无缝升级,新老程序互不影响。

下一篇,我们对比 Protobuf、JSON、XML 这三种常用数据格式的优缺点,帮你在实际项目中选择最合适的格式。

Logo

腾讯云面向开发者汇聚海量精品云计算使用和开发经验,营造开放的云计算技术生态圈。

更多推荐