Thrift 接口定义语言(interface description language)
说明: 本文适用于作为参考手册查阅。不适合为学习教程。
文档(Document)
一个文档即一个.thrift
文件
语法:
[1] Document ::= Header* Definition*
- Header: 头信息,一个文档可以有0到多个
Header
- Definition: 定义体, 一个文档可以有0到多个
Definition
头信息(Header)
头信息
语法:
[2] Header ::= Include | CppInclude | Namespace
- Thrift include: 引自其它
.thrift
文档 - C++ include: 引入C++自定义头文件
- namespace: 名字空间声明 (比如java 的包声明)
Thrift include
引入另一个文档中的所有 Thrift类型的 定义,使其在本文档中可见(可用)并在生成本文档代码时加入对应的引入信息(比如java import 对应的类)
语法:
[3] Include ::= 'include' Literal
- Literal: 字面量,这里指引入
.thrift
文件名称(全路径?待测试)
C++ Include
添加自定的C++ include,会输出到本文档对应的C++代码中
语法:
[4] CppInclude ::= 'cpp_include' Literal
- Literal: 字面量,这里指引入C++头文件文件名称(全路径?待验证,短期应该不会做)
namespace
名字空间 对应各语言的namespaces/package/module 等。 比如java的包
语法:
[5] Namespace ::= ( 'namespace' ( NamespaceScope Identifier ) |
( 'smalltalk.category' STIdentifier ) |
( 'smalltalk.prefix' Identifier ) ) |
( 'php_namespace' Literal ) |
( 'xsd_namespace' Literal )
- NamespaceScope 对就名字空间输出的作用域
- Identifier: 标识符,在这里指对应各语言的namespaces/package/module 等
注意 Smalltalk 两种类型的名字空间指令
- smalltalk.prefix: Prepended to generated classnames.
- smalltalk.category: Determines the category for generated classes.
- Smalltalk allows filing both classes and methods within classes into named groups. These named groups of methods are called categories. (不了解smalltack, 暂不作处理)
注意 The php_namespace directive will be deprecated at some point in the future in favor of the scoped syntax, but the scoped syntax is not yet supported for PHP. (不了解php, 暂不作处理)
注意 xsd_namespace
指令是Facebook内部有作用,对Thrift本身没啥作用。强烈建议不要使用
NamespaceScope
名字空间输出的作用域
语法:
[6] NamespaceScope ::= '*' | 'cpp' | 'java' | 'py' | 'perl' | 'rb' | 'cocoa' | 'csharp'
*
表示对所有的输出语言(不单独指定每种语言)cpp
生成代码时c++ 的 namespacejava
生成代码时Java对应的包名
定义指令(Definition)
文档的主体内容, 定义常量,对象,服务,异常等
语法:
[7] Definition ::= Const | Typedef | Enum | Senum | Struct | Union | Exception | Service
- Const: 定义常量
- Typedef: 类型别名
- Enum: 枚举
- Senum: 不知道是什么,但已经废弃了
- Struct: 结构体,
- Union: 联合体,
- Exception: 异常
- Service: 服务,包含方法
常量 (Const)
生成对应语言的常量定义
语法:
[8] Const ::= 'const' FieldType Identifier '=' ConstValue ListSeparator?
- FieldType: 字段类型,这里指常量类型
- Identifier: 标识符,在这里指常量名
- ConstValue: 常量值,这里指定义常量的值
- ListSeparator: 列表分隔符,如果常量后还有其它定义,需要加分隔符
类型别名(Typedef)
给类型启一个别名
语法:
[9] Typedef ::= 'typedef' DefinitionType Identifier
- DefinitionType: 预定义类型,这里别名的源类型,(注:可应该也可以是自定义类型,但自定义类型不太可能再命别名, 需要验证)
- Identifier: 标识符,在这里指别名
枚举(Enum)
创建一个枚举类型,默认第一个元素值为0,后一个比前一个大一;不能是负数
语法:
[10] Enum ::= 'enum' Identifier '{' (Identifier ('=' IntConstant)? ListSeparator?)* '}'
- Identifier: 标识符,这里指 枚举名称
- IntConstant: 常整数, 这里指 枚举量的值 (但有限制, 不能小于0, 后一个枚举昊默认比前一个大1)
- ListSeparator: 列表分隔符, 这里指 枚举量之间的分隔
zuo: 如果将第一个枚举量值设置为5,下一个为4, 再下一个默认为会是多少?
Senum(废弃)
Slist 各 Senum都被废弃了。用string 代替。 注:不太清楚这是什么,有了解的请告知下,不胜感激
语法:
[11] Senum ::= 'senum' Identifier '{' (Literal ListSeparator?)* '}'
结构体(Struct)
Thrift中基础的复合类型,一个结构体中的每个字段名必须唯一。
语法:
[12] Struct ::= 'struct' Identifier 'xsd_all'? '{' Field* '}'
- Identifier: 标识符,结构体名称(类名)
- Field: 字段, 指里指结构体中的字段
注意 xsd_all
又是Facebook 家内部的玩,不要用就对了
语法:
[12.x] Struct ::= 'struct' Identifier '{' Field* '}'
联合体(Union)
说是和 C++ union {}一样,(C++ 记不太清了,暂不译)
Unions are similar to structs, except that they provide a means to transport exactly one field of a possible set of fields, just like union {} in C++. Consequently, union members are implicitly considered optional (see requiredness).
语法:
[13] Union ::= 'union' Identifier 'xsd_all'? '{' Field* '}'
- Identifier: 标识符,这里指联合体名称
- Field: 字段,这里指联合体里的字段
注意 xsd_all
又是Facebook 家内部的玩意儿,不要用就对了 语法:
[13] Union ::= 'union' Identifier '{' Field* '}'
异常(Exception)
基本上和结构体是一样的,唯一的区别就是会继续目标语言的异常基类,以便无缝集成对应语言的异常处理
语法:
[14] Exception ::= 'exception' Identifier '{' Field* '}'
- Identifier: 标识符,这里指异常名称
- Field: 字段,这里指异常内的字段
服务(Service)
Thrift服务的功能接口,一个接口其实就是一系列方法(这是什么意思呢?) 一个服务可以继承另一个服务,表示它提供自己功能的同时也提供它继续接口的功能
语法:
[15] Service ::= 'service' Identifier ( 'extends' Identifier )? '{' Function* '}'
- Identifier: 标识符,这里指服务名称
- Function: 函数,这里指服务内的功能方法
字段 (Field)
字段定义语法
语法:
[16] Field ::= FieldID? FieldReq? FieldType Identifier ('= ConstValue)? XsdFieldOptions ListSeparator?
- FieldID: 字段ID
- FieldReq: 是否为必要字段
- FieldType: 字段类型,这里指定义字段的类型
- Identifier: 标识符,这里指字段名
- ConstValue: 常量值,这里指定义字段的默认值
- XsdFieldOptions: xsd选项,facebook内部定义,不要使用
- ListSeparator: 列表分隔符, 这里指定字段之间的分隔符
字段ID(Field ID)
字段ID, 整数常量
语法:
[17] FieldID ::= IntConstant ':'
- IntConstant: 常整数, 这里指 字段ID, 从1开始,依次累加
是否必要(Field Requiredness)
指定这个字段的值是否必须要有,同数据库相似吧
语法:
[18] FieldReq ::= 'required' | 'optional'
必要(required)
- Write: Required fields are always written and are expected to be set.
- Read: Required fields are always read and are expected to be contained in the input stream.
- Defaults values: are always written
可选 (optional)
Write: Optional fields are only written when they are set Read: Optional fields may, or may not be part of the input stream. Default values: are written when the isset flag is set
默认(default requiredness)
Write: In theory, the fields are always written. There are some exceptions to that rule, see below. Read: Like optional, the field may, or may not be part of the input stream. Default values: may not be written (see next section) Default requiredess is a good starting point. The desired behaviour is a mix of optional and required, hence the internal name "opt-in, req-out". Although in theory these fields are supposed to be written ("req-out"), in reality unset fields are not always written. This is especially the case, when the field contains a value, which by definition cannot be transported through thrift. The only way to achieve this is by not writing that field at all, and that's what most languages do.
关于默认值(Semantics of Default Values)
There are ongoing discussions about that topic, see JIRA for details. Not all implementations treat default values in the very same way, but the current status quo is more or less that default fields are typically set at initialization time. Therefore, a value that equals the default may not be written, because the read end will set the value implicitly. On the other hand, an implementation is free to write the default value anyways, as there is no hard restriction that prevents this.
The major point to keep in mind here is the fact, that any unwritten default value implicitly becomes part of the interface version. If that default is changed, the interface changes. If, in contrast, the default value is written into the output data, the default in the IDL can change at any time without affecting serialized data. (包含其它模块(客户端与服务端调用时)信息,暂不清楚,暂不作翻译, 后续补充)
XSD Options
Facebook 家内部的玩意儿,不要用就对了
[19] XsdFieldOptions ::= 'xsd_optional'? 'xsd_nillable'? XsdAttrs?
[20] XsdAttrs ::= 'xsd_attrs' '{' Field* '}'
函数 (Functions)
定义在服务中的函数
[21] Function ::= 'oneway'? FunctionType Identifier '(' Field* ')' Throws? ListSeparator?
[22] FunctionType ::= FieldType | 'void'
[23] Throws ::= 'throws' '(' Field* ')'
-
Field
:Function
中的Field
指函数的参数字段 -
FunctionType:
返回值有两个情况void
无返回值,但与oneway
有区别FieldType
其它类型
-
Throws
: 抛出异常, 当然需要定义好异常类 -
oneway
: 不需要等待返回,详见服务 -
Identifier: 标识符, 这里指函数名
类型 (Types)
可用类型,另见Thrift 类型介绍
字段类型 (FieldType)
字段类型,可以是标识符(自定义类型名称), 基本类型,容器类型
语法:
[24] FieldType ::= Identifier | BaseType | ContainerType
- Identifier: 标识符, 这里指自定义类型名称
- BaseType: 基本类型
- ContainerType: 容器类型
预定义类型 (DefinitionType)
Thrift 提供的类型
语法:
[25] DefinitionType ::= BaseType | ContainerType
- BaseType: 基本类型
- ContainerType: 容器类型
基本类型(BaseType)
Thrift 提供基本数据类型
语法:
[26] BaseType ::= 'bool' | 'byte' | 'i8' | 'i16' | 'i32' | 'i64' | 'double' | 'string' | 'binary' | 'slist'
详见: 基本类型
容器类型(ContainerType)
语法:
[27] ContainerType ::= MapType | SetType | ListType
字典类型(MapType)
键值对
语法:
[28] MapType ::= 'map' CppType? '<' FieldType ',' FieldType '>'
- CppType: C++类?
SetType
无序,唯一序列
语法:
[29] SetType ::= 'set' CppType? '<' FieldType '>'
- CppType:C++类?
列表(ListType)
有序序列
语法:
[30] ListType ::= 'list' '<' FieldType '>' CppType?
- CppType:C++类?
C++类型 (CppType)
语法:
[31] CppType ::= 'cpp_type' Literal
- Literal: 字面量, 这里指 对应类型的名称
常量 (Constant Values)
语法:
[32] ConstValue ::= IntConstant | DoubleConstant | Literal | Identifier | ConstList | ConstMap
- IntConstant: 整型常量
- DoubleConstant: 浮点型常量
- Literal: 字符型常量
- Identifier: 标识符, 这里指常量名
- ConstList: 常量列表
- ConstMap: 常量字典
整型常量(IntConstant)
可以是正整数,或负整数
语法:
[33] IntConstant ::= ('+' | '-')? Digit+
- Digit: 数字
浮点型常量(DoubleConstant)
实数或以科学计数方式表现
语法:
[34] DoubleConstant ::= ('+' | '-')? Digit* ('.' Digit+)? ( ('E' | 'e') IntConstant )?
- Digit: 数字
- IntConstant: 整型常量, 这里指科学计数的指数值
常量列表(ConstList)
看起来常量列表的元素也可以是常量列表
语法:
[35] ConstList ::= '[' (ConstValue ListSeparator?)* ']'
- ConstValue: 常量值,这里指 常量列表的元素值
- ListSeparator: 列表分隔符, 这里指常量元素值之间的分隔符
常量字典(ConstMap)
键值对常量
语法:
[36] ConstMap ::= '{' (ConstValue ':' ConstValue ListSeparator?)* '}'
- ConstValue: 常量值,这里指常量字典的 键和值
- ListSeparator: 列表分隔符, 这里指键值对之间的分隔符
基础定义(Basic Definitions)
字面量(Literal)
单引号或双引号都可以
语法:
[37] Literal ::= ('"' [^"]* '"') | ("'" [^']* "'")
验证能不能使用转义
标识符(Identifier)
语法:
[38] Identifier ::= ( Letter | '_' ) ( Letter | Digit | '.' | '_' )*
[39] STIdentifier ::= ( Letter | '_' ) ( Letter | Digit | '.' | '_' | '-' )*
列表分隔符(List Separator)
语法:
[40] ListSeparator ::= ',' | ';'
字母(Letters)
语法:
[41] Letter ::= ['A'-'Z'] | ['a'-'z']
数字(Digits)
语法:
[42] Digit ::= ['0'-'9']
示例
(后续添加)