【C/C++】进一步介绍idl编码
文章目录
- idl进一步介绍
- 一、message(结构体)的定义与使用
- 1. 基本结构体
- 二、结构体作为参数/返回值(在服务中用法)
- 三、结构体嵌套结构体 / 多层嵌套
- 四、repeated(数组/列表)
- 五、map(键值对)
- 六、oneof(类似 union 或可选字段)
- 七、结构体默认值说明
- 八、结构体字段的 optional 说明
- 九、reserved(保留字段名/编号)
- 十、结构体字段使用技巧和扩展性建议
- 延展字段(通用字段)
- 使用 Any 类型(跨模块灵活扩展)
- 十一、结构体 + 枚举联合使用
- 十二、结构体 + gRPC + HTTP REST API(gRPC-Gateway)
- 十三、结构体 + 扩展插件(Validate、OpenAPI)
- 十四、完整例子
- 总结:结构体 message 用法全览
idl进一步介绍
idl中所有常见语法和用法,包括结构体(message)、嵌套结构、枚举、oneof、map、repeated、结构体作为参数、默认值处理、扩展性技巧等等。
一、message(结构体)的定义与使用
1. 基本结构体
message User {int64 id = 1;string name = 2;int32 age = 3;
}
这就像 C++/Go 中的结构体,用于封装数据字段。
二、结构体作为参数/返回值(在服务中用法)
service UserService {rpc GetUser (UserRequest) returns (UserResponse);
}message UserRequest {int64 user_id = 1;
}message UserResponse {User user = 1; // 使用结构体作为字段
}
你可以在服务参数、返回值中嵌套任何结构体类型。这是 .proto
文件最常见的用法之一。
三、结构体嵌套结构体 / 多层嵌套
message Address {string city = 1;string street = 2;
}message User {int64 id = 1;string name = 2;Address address = 3; // 嵌套结构体
}
嵌套结构体可以定义在外部,也可以定义在结构体内部(建议外部定义,便于复用)。
四、repeated(数组/列表)
message Group {repeated User users = 1; // 表示用户列表
}
生成代码后,一般映射为:
- C++/Java:
std::vector<User>
- Python:
List[User]
- Go:
[]*User
五、map(键值对)
message UserTags {map<string, string> tags = 1; // 映射类型
}
注意事项:
- key 类型只支持:int32/int64/uint32/uint64/bool/string
- value 可以是任意类型,包括结构体
六、oneof(类似 union 或可选字段)
message PaymentMethod {oneof method {string credit_card = 1;string paypal = 2;string bank_transfer = 3;}
}
特点:
- 一次只能设置一个字段
- 在生成代码中通常会变成
union
或 enum + union 结构
七、结构体默认值说明
在 proto3 中,所有字段都有默认值,即便没有显式赋值:
类型 | 默认值 |
---|---|
string | "" |
bool | false |
数值类型 | 0 |
枚举 | 第一个定义项(一般是 *_UNSPECIFIED ) |
message | nullptr / default 构造 |
例:
message User {string name = 1; // 默认 ""int32 age = 2; // 默认 0bool active = 3; // 默认 false
}
八、结构体字段的 optional 说明
在 proto3 中,默认字段是 optional(可选),但没有“是否被设置”的标志。
若你要检查某字段是否显式设置过,可以使用 optional
关键字(从 proto3.15+ 支持):
message User {optional string nickname = 1; // 可检测“是否设置”
}
生成代码中会增加 has_nickname()
方法。
九、reserved(保留字段名/编号)
message User {reserved 3, 5 to 7;reserved "old_name", "legacy_field";
}
用于防止未来误用废弃字段编号或字段名,避免兼容性问题。
十、结构体字段使用技巧和扩展性建议
延展字段(通用字段)
message Metadata {map<string, string> tags = 1;repeated string labels = 2;
}
用于通用信息附加字段,方便扩展。
使用 Any 类型(跨模块灵活扩展)
import "google/protobuf/any.proto";message Event {string event_type = 1;google.protobuf.Any payload = 2;
}
用 Any
实现“任意结构体”传参,等价于 C++ 的 std::any
或 JSON 中的 object。
十一、结构体 + 枚举联合使用
enum Gender {GENDER_UNSPECIFIED = 0;MALE = 1;FEMALE = 2;
}message User {string name = 1;Gender gender = 2;
}
Gender
字段默认是第一个值 GENDER_UNSPECIFIED
,建议始终提供枚举的默认未定义值。
十二、结构体 + gRPC + HTTP REST API(gRPC-Gateway)
import "google/api/annotations.proto";service UserService {rpc GetUser (GetUserRequest) returns (User) {option (google.api.http) = {get: "/v1/users/{user_id}"};}
}message GetUserRequest {int64 user_id = 1;
}
结构体字段将自动映射为 URL 参数或 JSON body。
十三、结构体 + 扩展插件(Validate、OpenAPI)
结合 protoc-gen-validate
插件:
import "validate/validate.proto";message RegisterUserRequest {string email = 1 [(validate.rules).string.email = true];int32 age = 2 [(validate.rules).int32.gte = 18];
}
可生成自动验证代码,防止非法参数传入服务。
十四、完整例子
syntax = "proto3";package myapp.user;import "google/api/annotations.proto";message User {int64 id = 1;string name = 2;int32 age = 3;repeated string tags = 4;map<string, string> metadata = 5;
}message GetUserRequest {int64 user_id = 1;
}service UserService {rpc GetUser(GetUserRequest) returns (User) {option (google.api.http) = {get: "/v1/users/{user_id}"};}
}
总结:结构体 message 用法全览
用法类型 | 说明 |
---|---|
基本字段 | string/int32 等类型 |
嵌套结构体 | 字段类型是另一个 message |
repeated | 数组/列表 |
map | 键值对映射 |
oneof | 互斥字段 |
optional | 显式是否设置字段 |
reserved | 保留编号/字段名防止冲突 |
Any 类型 | 支持通用扩展结构 |
Enum | 搭配枚举定义状态类字段 |
REST 注解 | 支持 REST 接口映射(grpc-gateway) |