protobuf.js中如何定义值为对象数组的Map类型Protobuf字段
Protobuf 编码 Map<number, IOutput[]> 实现方案
不需要手动把现有Map转换为其他特殊格式,只要遵循Protobuf语法规则定义消息结构即可,protobuf.js 会自动完成JS原生Map和Protobuf二进制编码的双向转换。
注意:Protobuf 原生语法限制,
map字段的value不支持直接使用repeated(数组)类型,必须通过一层嵌套消息来承载数组结构,这是Protobuf的通用规则,和protobuf.js无关。
1. 编写.proto消息定义
先对齐你的TS接口定义对应消息,再定义数组包装消息,最后声明Map字段:
syntax = "proto3"; // 对应IOutput接口 message Output { string glyph = 1; string color = 2; optional string hex = 3; // 对应接口里的可选字段 int32 order = 4; } // 数组包装消息,承载Output对象数组 message OutputList { repeated Output items = 1; } // 业务根消息 message VisMapData { // key为数值类型对应JS Map的number键,value为包装后的数组消息 map<int32, OutputList> vis_map = 1; }
字段类型选择说明:
- JS侧Map的number类型key,proto里可以根据数值范围选
int32/uint32/int64等数值类型,普通场景用int32即可 - 可选字段
hex用optional修饰,编码时未传值会自动跳过,解码时对应字段为undefined,和TS可选逻辑一致
2. protobuf.js 侧使用
你现有的newVisMap实例不需要做任何手动格式转换,直接传入即可:
import protobuf from 'protobufjs'; // 加载proto文件 const root = await protobuf.load('./vis.proto'); const VisMapData = root.lookupType('VisMapData'); // 你原有的业务Map,不需要做结构转换 const newVisMap = new Map(); newVisMap.set(2, [ { glyph: 'circle', color: 'red', order: 1 }, { glyph: 'square', color: 'blue', hex: '0000ff', order: 2 } ]); // 构造Protobuf消息 const message = VisMapData.create({ // 注意:protobuf.js默认会把proto的下划线字段转小驼峰,即vis_map -> visMap // 如果初始化时配置了keepCase: true,这里要写原字段名vis_map visMap: newVisMap }); // 编码为二进制Buffer const encodedBuffer = VisMapData.encode(message).finish(); // 解码还原 const decodedData = VisMapData.decode(encodedBuffer); // decodedData.visMap 就是和原结构完全一致的 Map<number, IOutput[]>
常见注意点
- 如果要保留proto里的下划线命名不做小驼峰转换,加载proto时传入配置
{ keepCase: true }即可,此时构造消息时字段名要和proto保持一致写vis_map - 64位整数类型在JS里默认会转成Long对象,如果需要转成普通number,可以在加载时配置
{ longs: Number } - 不要尝试把Map强行转成对象数组来实现,Protobuf原生map类型的编码效率和使用便捷性都更高,protobuf.js对JS原生Map的适配已经非常成熟
内容的提问来源于stack exchange,提问作者hipsterstomper69
相关产品推荐
相关产品推荐

