写重复字段的函数如下:
void SetRepeatedInt32(Message * message, const FieldDescriptor * field, int index, int32 value) constvoid SetRepeatedString(Message * message, const FieldDescriptor * field, int index, std::string value) constvoid SetRepeatedEnumValue(Message * message, const FieldDescriptor * field, int index, int value) const // Set an enum field's value with an integer rather than EnumValueDescriptor. more..新增重复字段设计如下:
void AddInt32(Message * message, const FieldDescriptor * field, int32 value) constvoid AddString(Message * message, const FieldDescriptor * field, std::string value) const另外有一个较为重要的函数,其可以批量获取字段描述并将其放置到 vector 中:
void Reflection::ListFields(const Message & message, std::vector< const FieldDescriptor * > * output) const2.4 options 介绍PB 允许在 proto 中自定义选项并使用选项 。在定义 message 的字段时,不仅可以定义字段内容,还可以设置字段的属性,比如校验规则,简介等,结合反射,可以实现丰富丰富多彩的应用 。
下面来介绍下:
import "google/protobuf/descriptor.proto";extend google.protobuf.FieldOptions { optional uint32 attr_id = 50000; //字段id optional bool is_need_encrypt = 50001 [default = false]; // 字段是否加密,0代表不加密,1代表加密 optional string naming_conventions1 = 50002; // 商户组命名规范 optional uint32 length_min = 50003 [default = 0]; // 字段最小长度 optional uint32 length_max = 50004 [default = 1024]; // 字段最大长度 optional string regex = 50005; // 该字段的正则表达式}message SubMerchantInfo { // 商户名称 optional string merchant_name = 1 [ (attr_id) = 1, (is_encrypt) = 0, (naming_conventions1) = "company_name", (length_min) = 1, (length_max) = 80, (regex.field_rules) = "[a-zA-Z0-9]" ];使用方法如下:
#include <google/protobuf/descriptor.h>#include <google/protobuf/message.h>std::string strRegex = FieldDescriptor->options().GetExtension(regex);uint32 dwLengthMinp = FieldDescriptor->options().GetExtension(length_min);bool bIsNeedEncrypt = FieldDescriptor->options().GetExtension(is_need_encrypt);三、PB 反射的进阶使用第二章给出了 PB 反射,以及具体的使用细节,在本章中,作者结合自己日常的代码,给出 PB 反射一些使用场景 。并且以开发一个表单系统为例,讲一下 PB 反射在开发表单系统中的进阶使用 。
3.1 获取 PB 中所有非空字段在业务中,经常会需要获取某个 Message 中所有非空字段,形成一个 map<string,string>,使用 PB 反射写法如下:
#include "pb_util.h"#include <sstream>namespace comm_tools {int PbToMap(const google::protobuf::Message &message, std::map<std::string, std::string> &out) {#define CASE_FIELD_TYPE(cpptype, method, valuetype) case google::protobuf::FieldDescriptor::CPPTYPE_##cpptype: { valuetype value = reflection->Get##method(message, field); std::ostringstream oss; oss << value; out[field->name()] = oss.str(); break; }#define CASE_FIELD_TYPE_ENUM() case google::protobuf::FieldDescriptor::CPPTYPE_ENUM: { int value = reflection->GetEnum(message, field)->number(); std::ostringstream oss; oss << value; out[field->name()] = oss.str(); break; }#define CASE_FIELD_TYPE_STRING() case google::protobuf::FieldDescriptor::CPPTYPE_STRING: { std::string value = reflection->GetString(message, field); out[field->name()] = value; break; } const google::protobuf::Descriptor *descriptor = message.GetDescriptor(); const google::protobuf::Reflection *reflection = message.GetReflection(); for (int i = 0; i < descriptor->field_count(); i++) { const google::protobuf::FieldDescriptor *field = descriptor->field(i); bool has_field = reflection->HasField(message, field); if (has_field) { if (field->is_repeated()) { return -1; // 不支持转换repeated字段 } const std::string &field_name = field->name(); switch (field->cpp_type()) { CASE_FIELD_TYPE(INT32, Int32, int); CASE_FIELD_TYPE(UINT32, UInt32, uint32_t); CASE_FIELD_TYPE(FLOAT, Float, float); CASE_FIELD_TYPE(DOUBLE, Double, double); CASE_FIELD_TYPE(BOOL, Bool, bool); CASE_FIELD_TYPE(INT64, Int64, int64_t); CASE_FIELD_TYPE(UINT64, UInt64, uint64_t); CASE_FIELD_TYPE_ENUM(); CASE_FIELD_TYPE_STRING(); default: return -1; // 其他异常类型 } } } return 0;}} // namespace comm_tools
推荐阅读
- 绿杨春茶的冲泡方法,教你鉴别春茶的两方法
- 冬季雾霾来袭!中医教你清理肺部污染物
- 春季脖子易出问题 中医专家教你颈椎病防治之道
- 初春老犯困当心是脑梗 教你几招有效预防
- PHP微服务实践——手把手教你搭建PHP微服务
- 牛肉的做法 教你吃牛肉抗癌
- 咽喉炎吃什么好 教你食疗治咽喉炎
- 教你太极拳推手的5个姿势
- 教你读懂太极拳的八字决
- 路由器怎样重置密码?教你方法,简单实用很有效
