Thrift 接口定义语言 (IDL) 允许定义 Thrift 类型。 Thrift IDL 文件由 Thrift 代码生成器处理以生成各种目标语言的代码,从而支持 IDL 文件中定义的结构和服务。
Description
这是 Thrift IDL 的描述。
Document
每个 Thrift 文档包含 0 个或多个标题,后跟 0 个或多个定义。
[1] Document ::= Header* Definition*
Header
标头可以是 Thrift 包含、C++ 包含或命名空间声明。
[2] Header ::= Include | CppInclude | Namespace
Thrift Include
包含使来自另一个文件的所有符号可见(带有前缀)并将相应的包含语句添加到为此 Thrift 文档生成的代码中。
[3] Include ::= 'include' Literal
C++ Include
C++ 包含将自定义 C++ 包含添加到此 Thrift 文档的 C++ 代码生成器的输出中。
[4] CppInclude ::= 'cpp_include' Literal
Namespace
命名空间声明了哪些命名空间/包/模块/等。 此文件中的类型定义将为目标语言声明。 命名空间范围指示命名空间适用于哪种语言; “*”范围表示命名空间适用于所有目标语言。
[5] Namespace ::= ( 'namespace' ( NamespaceScope Identifier ) )
[6] NamespaceScope ::= '*' | 'c_glib' | 'cpp' | 'delphi' | 'haxe' | 'go' | 'java' | 'js' | 'lua' | 'netstd' | 'perl' | 'php' | 'py' | 'py.twisted' | 'rb' | 'st' | 'xsd'
Definition
[7] Definition ::= Const | Typedef | Enum | Senum | Struct | Union | Exception | Service
Const
[8] Const ::= 'const' FieldType Identifier '=' ConstValue ListSeparator?
Typedef
typedef 为类型创建一个备用名称。
[9] Typedef ::= 'typedef' DefinitionType Identifier
Enum
枚举创建具有命名值的枚举类型。 如果未提供常量值,则第一个元素的值为 0,或者任何后续元素的值都大于前一个值。 提供的任何常量值都必须是非负数。
[10] Enum ::= 'enum' Identifier '{' (Identifier ('=' IntConstant)? ListSeparator?)* '}'
senum
Senum(和 Slist)现在已弃用,都应替换为 String。
[11] Senum ::= 'senum' Identifier '{' (Literal ListSeparator?)* '}'
Struct
结构是 Thrift 中的基本组合类型。 每个字段的名称在结构中必须是唯一的。
[12] Struct ::= 'struct' Identifier 'xsd_all'? '{' Field* '}'
注意:xsd_all 关键字在 Facebook 内部有一些用途,但在 Thrift 本身中没有任何用途。 强烈建议不要使用此功能
Union
联合类似于结构,除了它们提供了一种方法来传输一组可能的字段中的一个字段,就像 C++ 中的 union {} 一样。 因此,工会成员被隐含地认为是可选的(请参阅必需性)。
[13] Union ::= 'union' Identifier 'xsd_all'? '{' Field* '}'
Exception
异常类似于结构,只是它们旨在与目标语言中的本地异常处理机制集成。 每个字段的名称在异常中必须是唯一的。
[14] Exception ::= 'exception' Identifier '{' Field* '}'
Service
服务为 Thrift 服务器提供的一组功能提供接口。 该接口只是一个功能列表。 一个服务可以扩展另一个服务,这只是意味着它除了提供自己的功能之外,还提供了扩展服务的功能。
[15] Service ::= 'service' Identifier ( 'extends' Identifier )? '{' Function* '}'
Field
[16] Field ::= FieldID? FieldReq? FieldType Identifier ('=' ConstValue)? XsdFieldOptions ListSeparator?
Field ID
[17] FieldID ::= IntConstant ':'
Field Requiredness
有两个明确的要求值,如果既没有给出必需的也没有给出可选的,第三个被隐式应用:默认要求。
[18] FieldReq ::= 'required' | 'optional'
必要性的一般规则如下:
必要的
- 写入:必填字段始终被写入并且预计会被设置。
- 读取:必填字段始终被读取,并应包含在输入流中。
- 默认值:始终写入
如果在读取期间缺少必填字段,则预期的行为是向调用者指示不成功的读取操作,例如 通过抛出异常或返回错误。
由于这种行为,必填字段极大地限制了有关软版本控制的选项。 因为它们必须在读取时出现,所以不能弃用这些字段。 如果将删除必填字段(或更改为可选字段),则数据在版本之间不再兼容。
可选的
- 写入:可选字段仅在设置时写入
- 阅读:可选字段可能是输入流的一部分,也可能不是。
- 默认值:设置 isset 标志时写入
大多数语言实现使用所谓的“isset”标志的推荐做法来指示是否设置了特定的可选字段。 仅写入设置了此标志的字段,相反,仅当从输入流中读取字段值时才设置该标志。
默认要求(隐式)
- 写入:理论上,字段总是被写入的。 该规则有一些例外,见下文。
- 阅读:与可选一样,该字段可能是也可能不是输入流的一部分。
- 默认值:可能不写(见下一节)
默认要求是一个很好的起点。 所需的行为是可选和必需的混合,因此内部名称为“opt-in, req-out”。 尽管理论上这些字段应该被写入(“req-out”),但实际上未设置的字段并不总是被写入。 当字段包含一个值时尤其如此,根据定义,该值不能通过 thrift 传输。 实现这一点的唯一方法是根本不编写该字段,这就是大多数语言所做的。
默认值的语义
有关该主题的讨论正在进行中,有关详细信息,请参阅 JIRA。 并非所有实现都以完全相同的方式处理默认值,但当前的现状或多或少是默认字段通常在初始化时设置。 因此,可能不会写入等于默认值的值,因为读取端会隐式设置该值。 另一方面,无论如何,实现都可以自由地写入默认值,因为没有硬性限制可以防止这种情况发生。
这里要记住的主要一点是,任何未写入的默认值都会隐式地成为接口版本的一部分。 如果更改该默认值,则界面会更改。 相反,如果将默认值写入输出数据,则 IDL 中的默认值可以随时更改,而不会影响序列化数据。
XSD 选项
注意:这些在 Facebook 有一些内部用途,但在 Thrift 中没有当前用途。 强烈建议不要使用这些选项。
[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* ')'
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
常数值
[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?)* '}'
基本定义
字面
[37] Literal ::= ('"' [^"]* '"') | ("'" [^']* "'")
标识符
[38] Identifier ::= ( Letter | '_' ) ( Letter | Digit | '.' | '_' )*
[39] STIdentifier ::= ( Letter | '_' ) ( Letter | Digit | '.' | '_' | '-' )*
列表分隔符
[40] ListSeparator ::= ',' | ';'
字母和数字
[41] Letter ::= ['A'-'Z'] | ['a'-'z']
[42] Digit ::= ['0'-'9']
保留关键字
"BEGIN", "END", "__CLASS__", "__DIR__", "__FILE__", "__FUNCTION__",
"__LINE__", "__METHOD__", "__NAMESPACE__", "abstract", "alias", "and", "args", "as",
"assert", "begin", "break", "case", "catch", "class", "clone", "continue", "declare",
"def", "default", "del", "delete", "do", "dynamic", "elif", "else", "elseif", "elsif",
"end", "enddeclare", "endfor", "endforeach", "endif", "endswitch", "endwhile", "ensure",
"except", "exec", "finally", "float", "for", "foreach", "from", "function", "global",
"goto", "if", "implements", "import", "in", "inline", "instanceof", "interface", "is",
"lambda", "module", "native", "new", "next", "nil", "not", "or", "package", "pass",
"public", "print", "private", "protected", "raise", "redo", "rescue", "retry", "register",
"return", "self", "sizeof", "static", "super", "switch", "synchronized", "then", "this",
"throw", "transient", "try", "undef", "unless", "unsigned", "until", "use", "var",
"virtual", "volatile", "when", "while", "with", "xor", "yield"
本文为从大数据到人工智能博主「xiaozhch5」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://lrting.top/backend/4143/
[…] 如果您对如何使用thrift定义语言不太了解,那么可以参考文章:Thrift接口定义语言 […]