Thriftについて学習してみた(個人用メモ)

Thriftを使用したいと思い、勉強してみた。
※個人用メモなので、間違った認識の場合があります。

## Thriftとは
 Thriftはインタフェース定義言語とコードジェネレータの総称である。
 コードジェネレータで生成されたコードを使用し、効果的にそしてシームレスにやりとりを行うことが可能である。
 現在の対応言語は、C++, Java, PHP, Ruby, Erlang, Perl, Haskell, C#, Cocoa, JavaScript, Node.js, Smalltalk, OCaml, Delphiである。
公式ページ https://thrift.apache.org/

## Thrift IDL
 ここでは、ThriftのIDLについて整理したい。
###使用可能な型
 Thriftは、基本型・コンテナ型・構造体・例外型・列挙型・共用体の6種類を使用することができる。
####基本型
|型名|説明|
|:-----|:---------|
|bool |論理値、trueもしくはfalseのこと|
|byte |1byteの整数|
|i16|2byteの整数|
|i32|4byteの整数|
|i64|8byteの整数|
|double|8byteの浮動小数点数|
|string|UTF8でエンコードされた文字列|
|binary|エンコードされていないバイドデータ|
####コンテナ型
|型名|説明|
|:--|:--|
|map|一意なキーと値の組み合わせ。C++のSTL map、JavaのHashMap、PHPの連想配列、Python/Rubyのdictionaryと同義|
|set|順序のない一意な要素のリスト。C++のSTL set、JavaのHashSet、Pytyonのsetと同義|
|list|順序付きの要素のリスト。C++のSTL vector、JavaのArrayListやスクリプト言語の配列と同義|

コンテナ型の定義は、c++の使い方と同様である。下記に定義例を示す。

```thrift:example.thrift
struct ExampleContainerDefinition
{
  1:map<i32, string> mapexample,
  2:set<i32> setexample,
  3:list<i32> listexample
}
```

####構造体
 Thriftの構造体はC言語の構造体ととてもよく似ている。一般的な宣言は、以下のように行う。

```thrift:example.thrift
struct ExampleStructure
{
  1:i32 id,
  2:string message
}
```

:の前に記載されている数値はFieldIDと呼ばれるものである。これは構造体内で一意の値である必要があり、サーバ・クライアントの両方で構造体の定義が合っているかを確認するためのものである。（別の構造体内に同じIDがあってもよい。)
他にも初期値の設定や構造体のデータの定義が必要であるか、任意であるかを定義することが可能である。
初期値は、フィールド名の後ろに=定数とすることで定義可能。
構造体のフィールドの必要性は、必要であればrequired、任意の場合はoptionalを:の後ろに記載すること。

```thrift:example.thrift
struct ExampleStructure
{
  1: required i32 id,
  2: optional string message="default"
}
```

#### 例外型
構造体と同様に、例外で使用する型も定義することが可能である。

```thrift:example.thrift
exception exampleException 
{
  1:i32 errorcode,
  2:string message
}
```

#### 列挙型
Thriftでも列挙型を使用することが可能である。列挙型は0から順に値が付けられるが、任意の値を定義することも可能である。

```thrift:example.thrift
enum exampleEnum1 {
  EnumA,
  EnumB,
  EnumC
}

enum exampleEnum2 {
  ONE = 1,
  TWO,
  FIVE = 5
}
```

#### 共用体
共用体は構造体と同様の定義を行うが、構造体とは異なる。
共用体は定義された複数のフィールドの中で、一つのフィールドしか使うことができない。
Thriftの共用体はC++の共用体のようなものである。
また上記の理由から共用体のフィールドにrequiredを使用することはできない。

### Services
Thriftで定義するServiceは、interfaceクラスのようなものである。
Serviceの中にはメソッドの集合を定義する。

```thrift:example.thrift
service exampleService 
{
  void set(1:i32 key,2:string value),
  string get(1:i32 key) throws (1:i32 errorcode),
  i32 size()
}
```

#### Method
Thriftでは、Service内にメソッドを定義することができる。
MethodはThriftが定義可能な型とvoidを使用することができる。
また引数には、構造体の宣言と同様にMethodの引数内で１意となるFieldIDの定義が必要である。

#### 例外
Thriftでは例外を定義することも可能である。
例外の定義は下記のように行う。

```thrift:example.thrift
exception exampleException1 
{
  1:i32 errorcode,
  2:string message
}

service exampleService 
{
  void testException(1:string arg) throws(1:exampleException error),
  void testException2(1:string arg) throws(1:exampleException error, 2:i32 error2)
}
```

上記のtestException2のように複数の例外を定義することも可能である。

#### oneway method
Service内で定義するmethodのうち、レスポンスを待つ必要がないmethodも定義可能である。
oneway methodを使用する場合は、戻り値は必ずvoidである必要がある。

```thrift:example.thrift
service exampleService
{
  oneway void show()
}
```

### その他Thriftのルール
ここではThriftの定義ファイルの記述ルールについて記載する。
#### コメント
コメントは、下記のように記述することができる。

```thrift:example.thrift
/*
 コメント
*/

//コメント
```
#### ヘッダー
ヘッダーには、include, cpp_include, namespaceの３種類を使用することができる。
includeは他のthriftファイルを使用するときに使用。
`include "example.thrift"`という風に定義する。
cpp_includeは不明。
namespaceはファイル内で定義した構造体や列挙型、Serviceの属するnamespaceを決定する。
namespaceは下記のように定義し、cppのところにはphpやjavaなどが入る。
namespaceは各言語ごとに定義する必要があることを注意したい。
`namespace cpp hoge`

#### 定数
Thriftの定義内で定数を定義することが可能である。
定数の宣言は、型名の前にconstを付与するだけである。
`const EXAMPLE_VALUE = 1`

#### Typedef
Thriftの定義内で型名を変更することが可能である。
型名の変更は、型名の前にtypedefを付与するだけである。
`typedef ExampleType i32`

#### フィールド名の命名ルール
フィールド名に使用できるのは、英数字と"\_"と"."である。
先頭は必ず英語または"\_"でなければいけない。