thrift-idl
1.基本类型
- bool:布尔值(true or false),一个字节
- byte:有符号字节
- i16:16位有符号整型
- i32:32位有符号整型
- i64:64位有符号整型
- double:64位浮点型
- string:encoding agnostic text or binary string
thrift不支持无符号整型
2.特殊类型
- binary:Blob(byte arrau) a sequence of unencoded bytes
这是string类型的一种变形,主要是为java使用
3.struct
thrift中的struct是定义为一种对象,和面向对象语言的class差不多,但是struct有一下约束:
- struct不能继承,但是可以嵌套,不能嵌套自己
- 其他成员都是有明确类型
- 成员是被正整数编号过的,其中编号不能重复。这是为了在传输过程中编码的使用
- 成员分隔符可以是逗号(,)或者是分号(?,而且可以混用。在使用中一般只使用一种
- 字段会有optional、required,也可以不指定。optional表示可选字段,如果不填充则不序列化;required是必填字段,如果不填充则报错,一定会序列化;不指定也表示可选字段,但是会序列化
- 每个字段可以设置默认值
- 同一个文件可以定义多个struct,也可以定义在不痛的文件中,进行include引入
数字标签作用非常大,但是随着项目的不断开发,也许字段会有变化,但是建议不要轻易修改这些字段,万一修改了一定要同步到服务器端、客户端
struct Report
{
1: required string msg, //必填字段,会序列化
2: optional i32 type = 0, //不是必填字段,默认值为0.因为有默认值,所以相当于是必填字段,会序列化。如果没有默认值则不会序列化
3: i32 time //没有默认值。不是必填,不管有没有填该字段,都会序列化
}
规范的struct定义中的每个域均会使用required或者 optional关键字进行标识。如果required标识的域没有赋值,Thrift将给予提示;如果optional标识的域没有赋值,该域将不会被序列化传输;如果某个optional标识域有缺省值而用户没有重新赋值,则该域的值一直为缺省值;如果某个optional标识域有缺省值或者用户已经重新赋值,而不设置它的__isset为true,也不会被序列化传输
4.容器(Containers)
thrift容器与目前流行变成语言的容器类型相对应,有三种可用容器类型:
- list:元素类型为t的有序表,容许元素重复
- set:元素类型为t的无需表,不容许元素重复
- map<k,t>:键类型为k,值类型为t的kv对,键不容许重复
容器中的元素类型可用是除了service外的任何合法的thrift类型(包括结构体和异常)。为了最大的兼容性,map的key最好是thrift的基本类型,有些语言不支持复杂类型的key,JSON协议只支持那些基本类型的key。
5.枚举(enum)
很多语言都有枚举,意义都一样。比如,当定义一个消息类型时,它只能是预定义的值列表中的一个,可以用枚举实现
- 编译器默认从0开始赋值
- 可以赋予某个常量某个整数
- 允许常量是十六进制整数
- 末尾没有符号分割
- 给常量赋缺省值时,使用常量的全称
枚举常量必须是32位的正整数
enum EnOpType {
CMD_OK = 0, // (0)
CMD_NOT_EXIT = 2000, // (2000)
CMD_EXIT = 2001, // (2001)
CMD_ADD = 2002 // (2002)
}
struct StUser {
1: required i32 userId;
2: required string userName;
3: optional EnOpType cmd_code = EnOpType.CMD_OK; // (0)
4: optional string language = “english”
}
6.常量定义和类型定义
thrift允许定义跨语言使用的常量,复杂的类型和结构体可用json形式表示
const i32 INT_CONST = 1234;
const EnOpType myEnOpType = EnOpType.CMD_EXIT; //2001
7.异常(Exceptions)
thrift结构体将转换成面向对象语言的类
异常在语法和功能上类似于结构体,差别是异常使用关键字exception,而且异常是继承某种语言的基础异常类
exception Extest {
1: i32 errorCode,
2: string message,
3: StUser userinfo
}
8.服务(Services)
服务的定义方法在语义上等同于面向对象语言中的接口。Thrift编译器会产生执行这些接口的client和server stub
Thrift编译器会根据选择的目标语言为server产生服务接口代码,为client产生stubs
service SeTest {
void ping(),
bool postTweet(1: StUser user);
StUser searchTweets(1:string name);
oneway void zip()
}
thrift编译器编译后的c++代码
class SeTestIf {
public:
virtual ~SeTestIf() {}
virtual bool AddUser(const StUser& user) = 0;
virtual void SearchUser(StUser& _return, const std::string& name) = 0;
virtual void NopNop() = 0;
};
9.命名空间(Namespace)
thrift的命名空间类似于c++中的namespace和java中的package,它们提供了一种组织(隔离)代码的简便方式。名字空间也可以用于解决类型定义中的名字冲突。
由于每种语言均有自己的命名空间定义方式(如Python中有module), thrift允许开发者针对特定语言定义namespace:
namespace cpp com.example.test
namespace java com.example.test
namespace php com.example.test
11.Includes
便于管理、重用和提高模块性/组织性,我们常常分割Thrift定义在不同的文件中。包含文件搜索方式与c++一样。Thrift允许文件包含其它thrift文件,用户需要使用thrift文件名作为前缀访问被包含的对象,如:
include "test.thrift"
...
struct StSearchResult {
1: in32 uid;
...
}
thrift文件名要用双引号包含,末尾没有逗号或者分号