Thrift IDL基于Thrift Types,而且考虑到Thrift Types的定义,Thrift IDL文件由Thrift代码生成器处理,为各类目标语言生成代码,以支持IDL文件中定义的结构和服务。php
1、Thrift类型系统(Thrift Types)
Thrift类型系统致力于让程序员尽量的使用原生数据类型,而不用关心他们所使用的编程语言。
一、基本类型
bool: A boolean value (true or false)
byte: An 8-bit signed integer
i16: A 16-bit signed integer
i32: A 32-bit signed integer
i64: A 64-bit signed integer
double: A 64-bit floating point number
string: A text string encoded using UTF-8 encoding
注意没有无符号整数类型。这是由于在许多编程语言中没有无符号整数类型。java
二、特殊类型
binary: a sequence of unencoded bytes
这是上面所提到的字符串类型的一种特殊形式,用于提供与Java更好的互操做性c++
三、结构体
结构体定义一个通用对象。本质上等价于OOP语言中的类,但没有继承。结构体有一组强类型字段,每一个字段具备惟一的名称标识符。字段能够具备在Thrift IDL中描述的各类注释(数字字段id、可选的默认值等)git
四、容器
容器是强类型容器,在大多数编程语言中能映射到经常使用的容器类型。
有三种容器类型:
list:元素的有序列表。翻译成STL vector、Java ArrayList、脚本语言中的本机数组等
set:惟一元素的无序集合。翻译成STL set、Java HashSet、Python中的set等。注意:PHP不支持集合,因此它与列表相似
map:值的惟一键的映射。翻译成STL map、Java HashMap、PHP关联数组、Python/Ruby字典等,虽然提供了默认值,可是类型映射不是显式固定的,已经添加了自定义代码生成器指令,以容许在各类目标语言中替换自定义类型。
容器元素能够是任何有效的Thrift类型。程序员
为了最大的兼容性,map的键类型应该是基本类型,而不是结构体或容器类型。有些语言不支持本地映射类型中的更复杂的键类型。此外,JSON协议只支持基类型的关键类型。编程
五、异常
异常在功能上等同于结构,除了它们在每一个目标编程语言中适当地从本机异常基类继承,以便在任何给定语言中无缝地与本机异常处理集成。数组
六、服务
服务是使用Thirft类型定义的。服务的定义在语义上等同于在面向对象编程中定义接口(或纯虚拟抽象类)。Thrift编译器生成实现接口的全功能客户端和服务器代码桩(stubs)。服务器
服务由一组命名函数组成,每一个函数都有一个参数列表和一个返回类型。编程语言
注意,除了全部其余定义的Thrift类型以外,void是函数返回的有效类型。此外,能够向void函数添加oneway修饰符关键字,该函数将生成不等待响应的代码。注意,纯void函数将返回一个响应给客户端,该响应保证操做已经在服务器端完成。用oneway方法调用客户端只能保证请求在传输层成功。同一客户机的oneway方法调用能够由服务器在并行/乱序的状况下执行。函数
2、Thrift接口描述语言
一、Document
每一个Thrift文档包含0或更多的头,后面跟着0或更多的定义。
[1] Document ::= Header* Definition*
二、Header
header是一个Thrift include,一个c++ include,或者一个名称空间声明。
[2] Header ::= Include | CppInclude | Namespace
(1) Thrift Include
include使来自另外一个文件的全部符号均可见(带有前缀),并将相应的include语句添加到为此Thrift文档生成的代码中。
[3] Include ::= 'include' Literal
(2)C++ Include
c++ include中添加了一个自定义c++程序,包括用于这个Thrift文档的c++代码生成器的输出。
[4] CppInclude ::= 'cpp_include' Literal
三、Namespace
名称空间(namespace)声明哪一个名称空间(namespace)/包(package)/模块(module)等。此文件中的类型定义将为目标语言声明。名称空间范围指示该名称空间应用于哪一种语言;“*”的范围指示名称空间适用于全部目标语言。
[5] Namespace ::= ( 'namespace' ( NamespaceScope Identifier ) |
( 'smalltalk.category' STIdentifier ) |
( 'smalltalk.prefix' Identifier ) ) |
( 'php_namespace' Literal ) |
( 'xsd_namespace' Literal )
[6] NamespaceScope ::= '*' | 'cpp' | 'java' | 'py' | 'perl' | 'rb' | 'cocoa' | 'csharp'
四、Definition
[7] Definition ::= Const | Typedef | Enum | Senum | Struct | Union | Exception | Service
五、Const
[8] Const ::= 'const' FieldType Identifier '=' ConstValue ListSeparator?
六、Typedef
类型定义为类型建立另外一个名称。
[9] Typedef ::= 'typedef' DefinitionType Identifier
七、Enum
枚举建立带有命名值的枚举类型。若是没有提供常量值,则第一个元素的值为0,或任何后续元素的值大于前一个值。所提供的任何常数值都必须是非负的。
[10] Enum ::= 'enum' Identifier '{' (Identifier ('=' IntConstant)? ListSeparator?)* '}'
八、Senum
Senum(和Slist)如今已被弃用,应该用字符串替换它们。
[11] Senum ::= 'senum' Identifier '{' (Literal ListSeparator?)* '}'
九、Struct
结构体是Thrift的基本组成类型。每一个字段的名称必须在结构体中是惟一的。
[12] Struct ::= 'struct' Identifier 'xsd_all'? '{' Field* '}'
十、Union
union相似于struct,只不过它们提供了一种方法来传输一组可能的字段,就像c++中的union{}同样。所以,联合成员被隐式地认为是可选的(请参阅require)。
[13] Union ::= 'union' Identifier 'xsd_all'? '{' Field* '}'
十一、Exception
异常与结构类似,除了它们旨在与目标语言中的本机异常处理机制集成。每一个字段的名称必须在异常中是惟一的。
[14] Exception ::= 'exception' Identifier '{' Field* '}'
十二、Service
服务为Thrift server提供了接口。接口只是一个函数列表。服务能够扩展另外一个服务,这仅仅意味着它除了提供本身的服务以外还提供扩展服务的功能。
[15] Service ::= 'service' Identifier ( 'extends' Identifier )? '{' Function* '}'
1三、Field
[16] Field ::= FieldID? FieldReq? FieldType Identifier ('= ConstValue)? XsdFieldOptions ListSeparator?
1四、Field ID
[17] FieldID ::= IntConstant ':'
1五、Field Requiredness
有两个显式的Requiredness值,第三个是应用的含义(若是既不是必需的也不是可选的):默认Requiredness。
[18] FieldReq ::= 'required' | 'optional'
Requiredness的通常规则以下:
required
Write: 字段老是被写入,而且指望被设置。
Read: 字段老是被读取,而且指望包含在输入流中。
Defaults values:老是被写入。
若是在读取过程当中缺乏一个required字段,那么预期的行为是向调用者指出一个失败的读取操做,例如抛出异常或返回错误。
因为这种行为,required字段极大地限制了软版本控制的选项。由于它们必须在读取时显示,因此不能废弃字段。若是须要的字段被删除(或更改成可选字段),则版本之间的数据再也不兼容。
optional
Write: 字段只在设置时才写入。
Read: 字段多是,也可能不是输入流的一部分。
Defaults values:在设置isset标志时被写入。
大多数语言实现都使用所谓的“isset”标志,以指示是否设置了特定的可选字段。只有具备此标志的字段才被写入,相反,只有在从输入流读取字段值时才会设置标志。
default requiredness (implicit)
Write: 在理论上,字段老是被写入。这个规则有一些例外,见下文。
Read: 与可选字段同样,字段多是或不是输入流的一部分。
Defaults values:可能不写(见下一节)
默认需求是一个很好的起点。所指望的行为是可选的和必需的混合,所以内部名称为“opt-in, req-out”。虽然理论上这些字段应该是写出来的(“req-out”),但在现实中,未设置的字段并不老是写出来的。特别是当字段包含一个不能经过Thrift进行传输的值时。这一点的惟一方法是彻底不编写这个字段,而这正是大多数语言所作的。
默认值的语义(Semantics of Default Values)
关于这个话题还有不少讨论。并非全部的实现都以相同的方式处理默认值,可是当前的状态或多或少是默认字段一般在初始化时设置的。所以,可能不会写入等于默认值的值,由于读端将隐式地设置值。另外一方面,不管如何,实现均可以自由地写入默认值,由于没有硬限制能够防止这种状况。
这里要记住的主要一点是,任何未写入的默认值都隐式地成为接口版本的一部分。若是这个默认值改变了,那么接口就会改变。相反,若是将默认值写入输出数据,则IDL中的默认值能够随时更改,而不会影响序列化数据。
1六、Functions
[21] Function ::= 'oneway'? FunctionType Identifier '(' Field* ')' Throws? ListSeparator?
[22] FunctionType ::= FieldType | 'void'
[23] Throws ::= 'throws' '(' Field* ')'
1七、Types
[24] FieldType ::= Identifier | BaseType | ContainerType
[25] DefinitionType ::= BaseType | ContainerType
[26] BaseType ::= 'bool' | 'byte' | 'i8' | 'i16' | 'i32' | 'i64' | 'double' | 'string' | 'binary' | 'slist'
[27] ContainerType ::= MapType | SetType | ListType
[28] MapType ::= 'map' CppType? '<' FieldType ',' FieldType '>'
[29] SetType ::= 'set' CppType? '<' FieldType '>'
[30] ListType ::= 'list' '<' FieldType '>' CppType?
[31] CppType ::= 'cpp_type' Literal
1八、Constant Values
[32] ConstValue ::= IntConstant | DoubleConstant | Literal | Identifier | ConstList | ConstMap
[33] IntConstant ::= ('+' | '-')? Digit+
[34] DoubleConstant ::= ('+' | '-')? Digit* ('.' Digit+)? ( ('E' | 'e') IntConstant )?
[35] ConstList ::= '[' (ConstValue ListSeparator?)* ']'
[36] ConstMap ::= '{' (ConstValue ':' ConstValue ListSeparator?)* '}'
1九、基本定义
Literal
[37] Literal ::= ('"' [^"]* '"') | ("'" [^']* "'")
Identifier
[38] Identifier ::= ( Letter | '_' ) ( Letter | Digit | '.' | '_' )*
[39] STIdentifier ::= ( Letter | '_' ) ( Letter | Digit | '.' | '_' | '-' )*
List Separator
[40] ListSeparator ::= ',' | ';'
Letters and Digits
[41] Letter ::= ['A'-'Z'] | ['a'-'z']
[42] Digit ::= ['0'-'9']