Proto文件相关知识
百度Apollo的数据结构常用proto文件来定义, proto
文件允许你以类似于C++结构体或类的方式定义数据结构。你可以在这个文件中定义简单数据类型、枚举、消息类型等。
基于proto
文件,Protocol Buffers编译器(protoc
)可以自动生成对应的C++类。这些类提供了序列化和反序列化的方法,以及各种数据操作的方法。
本文是对proto用法的一些积累:
Protocol Buffers 的基本用法
-
定义数据结构(.proto 文件):
你需要首先编写一个
.proto
文件,用于定义你的数据结构。例如,定义一个简单的Graph
和Node
:syntax = "proto3";message Node {string lane_id = 1;string road_id = 2;// 其他字段... }message Graph {repeated Node node = 1;// 其他字段... }
syntax = "proto3";
指定使用 Protocol Buffers 的第三个版本语法。message
用于定义数据结构。- 每个字段都有一个唯一的编号(如
1
,2
),用于在序列化时标识字段。
-
生成代码:
使用
protoc
编译器,根据.proto
文件生成目标编程语言的代码。例如,生成 C++ 代码:protoc --cpp_out=. graph.proto
这会生成相应的
.pb.h
和.pb.cc
文件,你可以在项目中包含并使用这些生成的类。
例如Apollo中的node_creator.h
中,便引用了以下头文件:
#pragma once
#include <string>
#include "modules/map/proto/map_lane.pb.h"
#include "modules/routing/proto/routing_config.pb.h"
#include "modules/routing/proto/topo_graph.pb.h"
namespace apollo {
namespace routing {
namespace node_creator {
void GetPbNode(const hdmap::Lane& lane, const std::string& road_id,const RoutingConfig& routingconfig, Node* const node);
} // namespace node_creator
} // namespace routing
} // namespace apollo
-
使用生成的类:
在代码中,你可以像使用普通类一样使用生成的 Protobuf 类。例如,使用 C++:
#include "graph.pb.h" void Example() {Graph graph;Node* node = graph.add_node();node->set_lane_id("lane_123");node->set_road_id("road_456");// 设置其他字段...// 序列化为二进制std::string binary_data;graph.SerializeToString(&binary_data);// 反序列化Graph new_graph;new_graph.ParseFromString(binary_data); }
1proto文件中的关键字
在 Protocol Buffers(Protobuf)中,repeated
是一个关键字,用于定义一个可以包含零个或多个指定类型元素的字段。具体到您提到的 repeated Node node
,它的含义如下:
repeated Node node
的含义
repeated
:这是 Protobuf 中的一个修饰符,表示该字段可以出现多次,类似于数组、列表或集合。Node
:这是一个自定义的消息类型(即另一个message
定义),表示每个元素的类型。node
:这是字段的名称,用于在代码中访问该字段。
示例 .proto
文件
以下是一个完整的 .proto
文件示例,展示了如何使用 repeated
关键字:
syntax = "proto3";message Node {string lane_id = 1;string road_id = 2;// 其他字段...
}message Graph {repeated Node node = 1; // 这是您提到的行// 其他字段...
}
repeated
字段的作用
使用 repeated
声明的字段允许在一个消息中包含多个相同类型的元素。在上述示例中,Graph
消息可以包含多个 Node
元素。这样设计的好处包括:
- 灵活性:可以根据需要添加任意数量的
Node
元素,而不需要预先定义具体的数量。 - 动态扩展:在序列化和反序列化过程中,Protobuf 会自动处理这些重复的元素,使得数据交换更加高效和简洁。
生成代码中的 repeated
字段
当使用 protoc
编译器根据 .proto
文件生成代码时,repeated
字段会生成一组专门的方法,用于操作这些重复的元素。以下以 C++ 为例,说明 repeated Node node
会生成哪些方法:
class Graph : public ::google::protobuf::Message {
public:// 获取 node 的数量int node_size() const;// 获取指定索引的 Nodeconst Node& node(int index) const;Node* mutable_node(int index);// 添加一个新的 NodeNode* add_node();// 获取所有 Node 的只读引用const ::google::protobuf::RepeatedPtrField<Node>& node() const;// 获取所有 Node 的可变引用::google::protobuf::RepeatedPtrField<Node>* mutable_node();// 清除所有 Nodevoid clear_node();// 其他 Protobuf 生成的方法...
};
各方法的作用
-
int node_size() const;
- 返回
node
字段中Node
元素的数量。
- 返回
-
const Node& node(int index) const;
- 返回指定索引处的
Node
元素的只读引用。
- 返回指定索引处的
-
Node* mutable_node(int index);
- 返回指定索引处的
Node
元素的可变引用,允许修改该元素。
- 返回指定索引处的
-
Node* add_node();
- 在
node
字段末尾添加一个新的Node
元素,并返回该新元素的可变引用。
- 在
-
const ::google::protobuf::RepeatedPtrField<Node>& node() const;
- 返回
node
字段中所有Node
元素的只读引用,通常用于遍历。
- 返回
-
::google::protobuf::RepeatedPtrField<Node>* mutable_node();
- 返回
node
字段中所有Node
元素的可变引用,允许批量修改。
- 返回
-
void clear_node();
- 清除
node
字段中所有的Node
元素。
- 清除
使用示例
以下是一个使用生成的 Graph
类操作 repeated Node node
字段的示例:
#include "graph.pb.h" // 生成的 Protobuf 头文件void Example() {Graph graph;// 添加一个新的 NodeNode* node1 = graph.add_node();node1->set_lane_id("lane_123");node1->set_road_id("road_456");// 添加另一个 NodeNode* node2 = graph.add_node();node2->set_lane_id("lane_789");node2->set_road_id("road_012");// 获取 Node 的数量int count = graph.node_size();std::cout << "Number of nodes: " << count << std::endl;// 遍历所有 Nodefor (int i = 0; i < graph.node_size(); ++i) {const Node& node = graph.node(i);std::cout << "Node " << i << ": lane_id = " << node.lane_id()<< ", road_id = " << node.road_id() << std::endl;}// 清除所有 Nodegraph.clear_node();
}
总结
repeated
关键字:用于定义可以包含多个相同类型元素的字段,类似于数组或列表。- 自动生成的方法:Protobuf 根据
repeated
字段生成一系列方便操作的方法,如add_node()
,node_size()
,node(int index)
等。 - 灵活性和效率:
repeated
字段提供了高度的灵活性,允许动态添加和管理多个元素,同时保持高效的序列化和反序列化性能。
如果您有更多关于 Protobuf 或 repeated
字段的具体问题,请随时提问!