我正在参加「掘金·启航计划」
Thrift是一套包含序列化功能和支持服务通信的RPC框架,主要包含三大部分:代码生成、序列化框架、RPC框架,大致相当于protoc + protobuffer + grpc,并且支持大量语言,保证常用功能在跨语言间功能一致,是一套全栈式的RPC解决方案。
Thrift数据类型
即 IDL 中的基础类型有 10 种
bool布尔型,false | true
bytebyte
i8int8——不推荐使用
i16int16
i32int32
i64int64
double双精度浮点型
string字符串
binary二进制 byte[]
-
slist
Thrift容器类型
// Map 简单的 key-value 对,key 不可以重复,`<keyType, valueType>` 用来指定 key 和 value 的类型
// 简单的 map 类型
map <string, i8>
// 嵌套 map 类型
map <map <string, i32>, i64>
// 更多的嵌套可能是这样的
map <string, map<string, string>>
map <string, set<i32>>
// Set 不重复的数据集合,`<type>` 指定集合中元素的类型
set <string>
set <map <string, bool>>
// List 类似数组,元素可重复, `<type>` 指定集合中元素的类型
list <i64>
list <set <string>>
list <map<string, set<i8>>>
字段权限
-
required:
- 写:必须字段始终写入,并且应该设置这些字段。
- 读:必须字段始终读取,并且它们将包含在输入流中
- 注意:如果一个必须字段在读的时候丢失,则会抛出异常或返回错误,所以在版本控制的时候,要严格控制字段的必选和可选,必须字段如果被删或者改为可选,那将会造成版本不兼容。
-
optional:
- 写:可选字段仅在设置时写入
- 读:可选字段可能是也可能不是输入流的一部分
-
default:
- 写:理论上总是写入,但是有一些特例
- 读:跟optional一样
- 默认类型是required和optional的结合,可选输入(读),必须输出(写)。
举个🌰
- 完整的thrift文件定义
struct ExampleRequestParam {
1: optional i64 ReqOptional
2: required i64 ReqRequired
3: i64 ReqNone
4: optional Info ReqInfoOptional
5: required Info ReqInfoRequired
6: Info ReqInfoNone
}
struct Info {
1: optional i64 InfoInsideOptional
2: required i64 InfoInsideRequired
3: i64 InfoInsideNone
}
struct ExampleResponse {
1: optional i64 RespOptional
2: required i64 RespRequired
3: i64 RespNone
4: optional Info RespInfoOptional
5: required Info RespInfoRequired
6: Info RespInfoNone
}
// ------ service ------
service ExampleService {
ExampleResponse Example(1: required ExampleRequestParam req)
}
- 请求参数(对应字段权限中的“读”):
蓝色:可以删除不写
黄色:必须写
{
"ReqOptional": 1, // 可以删除不写,也可以写
"ReqRequired": 1, // 必须写
"ReqNone": 1, // 可以删除不写,也可以写,跟OPtional保持一致
"ReqInfoOptional": {..}, // 可以删除不写,也可以写
"ReqInfoRequired":{ // 必须写该结构体
"InfoInsideOptional": 2,
"InfoInsideRequired": 2,
"InfoInsideNone": 2
},
"ReqInfoNone": {..} // 可以删除不写,也可以写, 跟OPtional保持一致
}
- 返回参数(对应字段权限中的“写”),以Golang为例:
蓝色:可以删除不写
黄色:必须写
type ExampleResponse struct {
RespOptional *int64 `thrift:"RespOptional,1,optional" json:"RespOptional,omitempty"`
RespRequired int64 `thrift:"RespRequired,2,required" json:"RespRequired"`
RespNone int64 `thrift:"RespNone,3" json:"RespNone"`
RespInfoOptional *Info `thrift:"RespInfoOptional,4" json:"RespInfoOptional,omitempty"`
RespInfoRequired *Info `thrift:"RespInfoRequired,5,required" json:"RespInfoRequired"`
RespInfoNone *Info `thrift:"RespInfoNone,6" json:"RespInfoNone"`
}
func Service(ctx context.Context ,req xx.ExampleRequestParam) (xx.ExampleResponse, error){
resp
resp := xx.ExampleResponse{
RespOptional: 1, // 可以不写,Optional,
RespRequired: 1, // 可以不写,基础类型在外层初始化时自动赋值为0
RespNone: 1, // 可以不写,基础类型在外层初始化时自动赋值为0,与Required保持一致
RespInfoOptional: .., // 可以不写,Optional
RespInfoRequired: &xx.Info{ // 必须写,初始化结构体,因为无默认值,被认为是nil,所以必须在这里初始化
"InfoInsideOptional": 2,
"InfoInsideRequired": 2,
"InfoInsideNone": 2
},
RespInfoNone:&xx.Info{ // 必须写,与required保持一致
"InfoInsideOptional": 2,
"InfoInsideRequired": 2,
"InfoInsideNone": 2
},
}
... // 业务逻辑处理
return resp, nil
}
总结:
-
针对请求参数
- optional/default 可以不用写;
- required必须写;
-
针对(代码中)返回值
-
optional 可以不用写;
-
required分情况(由于Golang的代码特性)
- 基础类型,默认值不为nil,可以不用初始化,会自动默认赋值为默认值;
- 非基础类型,默认值为nil,必须初始化,否则在会识别不到有该返回值,导致报错。
-