Thrift 接口定义语言(interface description language)参考手册

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类型的 定义,使其在本文档中可见(可用)并在生成本文档代码时加入对应的引入信息(比如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++ 的 namespace
  • java 生成代码时Java对应的包名

定义指令(Definition)

文档的主体内容, 定义常量,对象,服务,异常等

语法:

[7]  Definition      ::=  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?

字段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: 抛出异常, 当然需要定义好异常类

  • Field: Throws 后台面的这个Field, 我觉得应该是Exception才对, 需要验证(计划)

  • oneway: 不需要等待返回,详见服务

  • Identifier: 标识符, 这里指函数名

类型 (Types)

可用类型,另见Thrift 类型介绍

字段类型 (FieldType)

字段类型,可以是标识符(自定义类型名称), 基本类型,容器类型

语法:

[24] FieldType       ::=  Identifier | BaseType | ContainerType

预定义类型 (DefinitionType)

Thrift 提供的类型

语法:

[25] DefinitionType  ::=  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 '>'

SetType

无序,唯一序列

语法:

[29] SetType         ::=  'set' CppType? '<' FieldType '>'

列表(ListType)

有序序列

语法:

[30] ListType        ::=  'list' '<' FieldType '>' CppType?

C++类型 (CppType)

语法:

[31] CppType         ::=  'cpp_type' Literal
  • Literal: 字面量, 这里指 对应类型的名称

常量 (Constant Values)

语法:

[32] ConstValue      ::=  IntConstant | DoubleConstant | Literal | Identifier | ConstList | ConstMap

整型常量(IntConstant)

可以是正整数,或负整数

语法:

[33] IntConstant     ::=  ('+' | '-')? Digit+

浮点型常量(DoubleConstant)

实数或以科学计数方式表现

语法:

[34] DoubleConstant  ::=  ('+' | '-')? Digit* ('.' Digit+)? ( ('E' | 'e') 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']

示例

(后续添加)

来源

译自 https://thrift.apache.org/docs/idl

转载于:https://my.oschina.net/u/915811/blog/864855

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
跨语言 RPC 框架 Thrift 是一个开源的高效通信协议和序列化框架,可以用于构建跨语言的客户端和服务器端应用程序。 下面是一个简单的 Thrift 实战示例: 1. 定义 Thrift 文件:首先,我们需要创建一个 .thrift 文件来定义我们的 RPC 接口和数据结构。例如,我们可以创建一个名为 "calculator.thrift" 的文件,其中包含以下内容: ``` namespace java com.example.calculator namespace py calculator service CalculatorService { i32 add(1: i32 num1, 2: i32 num2), i32 subtract(1: i32 num1, 2: i32 num2), i32 multiply(1: i32 num1, 2: i32 num2), double divide(1: double num1, 2: double num2) } ``` 2. 生成代码:使用 Thrift 编译器将 .thrift 文件生成相应语言的代码。例如,我们可以使用以下命令生成 Java 和 Python 的代码: ``` thrift --gen java calculator.thrift thrift --gen py calculator.thrift ``` 这将生成相应语言的客户端和服务器端代码。 3. 实现服务器端:在服务器端,我们需要实现 Thrift 定义接口。对于 Java,我们可以编写一个实现 CalculatorService 接口的类,并在该类中实现具体的业务逻辑。对于 Python,我们可以编写一个类似的实现。 4. 启动服务器:在服务器上启动 Thrift 服务器,以便接受客户端的请求。不同语言的服务器实现方式可能有所不同,但通常都需要提供一个监听指定端口的入口。 5. 实现客户端:在客户端,我们可以使用生成的客户端代码来调用服务器端的接口。对于 Java,我们可以创建一个 Thrift 客户端,并使用生成的代码来调用服务器端提供的方法。对于 Python,我们可以编写相应的客户端代码。 6. 运行客户端:运行客户端代码,通过网络连接到服务器,并发送请求调用服务器端的方法。 以上是一个简单的 Thrift 实战示例。请注意,具体的实现方式和步骤可能因语言和框架而异,但基本原理是相似的。Thrift 还支持更多高级特性,如异步调用、连接池等,可以根据具体需求进行扩展和优化。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值