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']