概略
.proto
ファイルを作成し、protoc
というコンパイラで各言語向けのスタブファイルを作成します。
helloworld.proto
の例は以下のようなものです。
syntax = "proto3"; package helloworld; service Greeter { rpc SayHello (HelloRequest) returns (HelloReply) {} } message HelloRequest { string name = 1; } message HelloReply { string message = 1; }
service
ブロックに rpc
キーワードでRPC(Remote Procedure Call) のインターフェースを定義します。
message
キーワードで、やり取りするメッセージフォーマットを定義します。
ファイルの先頭には syntax
キーワードで構文を指定します。
指定しなかった場合には proto2
が指定されたものとして扱われます。
package
キーワードでパッケージを定義します。
コメントは C形式のコメントが利用できます。
行コメントには //
、ブロックコメントには /* */
を使います。
メッセージタイプ
メッセージにはフィールドを定義できます。
message SearchRequest { string query = 1; int32 page_number = 2; int32 result_per_page = 3; }
フィールドにはフィールド番号を割り当てます。
この番号はメッセージバイナリ形式での識別子として利用されます。
フィールドを削除した場合などで、削除済みのフィールドを再利用されないようにするには reserved
キーワードを使うことでフィールド番号やフィールド名を予約することができます。
message Foo { reserved 2, 15, 9 to 11; reserved "foo", "bar"; }
proto2
では required
や optional
が使えたが proto3
で廃止されました。
スカラー値型
スカラー値型は以下のようなものが利用でき、コンパイル後の各言語との対応は以下のようになります。
.proto Type | Java Type | Python Type | Go Type | C# Type |
---|---|---|---|---|
double | double | float | float64 | double |
float | float | float | float32 | float |
int32 | int | int | int32 | int |
int64 | long | int/long | int64 | long |
uint32 | int | int/long | uint32 | uint |
uint64 | long | int/long | uint64 | ulong |
sint32 | int | int | int32 | int |
sint64 | long | int/long | int64 | long |
fixed32 | int | int/long | uint32 | uint |
fixed64 | long | int/long | uint64 | ulong |
sfixed32 | int | int | int32 | int |
sfixed64 | long | int/long | int64 | long |
bool | boolean | bool | bool | bool |
string | String | str/unicode | string | string |
bytes | ByteString | str | []byte | ByteString |
サービス
RPC サービスのインターフェイスを以下のように定義できます。
service SearchService { rpc Search (SearchRequest) returns (SearchResponse); }
SearchRequest
を引数に取り SearchResponse
を返す RPC サービスを定義しています。
コンパイラは選択した言語でサービスのインターフェイスとスタブを生成します。
入れ子のメッセージ
メッセージは他のメッセージを使い構造化することができます。
message SearchResponse { Result results = 1; } message Result { string url = 1; string title = 2; }
メッセージ内に直接定義することもできます。
message SearchResponse { message Result { string url = 1; string title = 2; repeated string snippets = 3; } repeated Result results = 1; }
内部のメッセージは以下のようにピリオドでつないで使うことができます。
message SomeOtherMessage { SearchResponse.Result result = 1; }
enum
enum
キーワードで enum を定義できます。
enum Corpus { UNIVERSAL = 0; WEB = 1; IMAGES = 2; LOCAL = 3; }
フィールド番号として、必ず最初に 0 を指定する必要があります。
フィールド番号 0 のものがデフォルト値として扱われます。
メッセージの中に入れ子で定義することもできます。
message SearchRequest { string query = 1; int32 page_number = 2; enum Corpus { UNIVERSAL = 0; WEB = 1; IMAGES = 2; LOCAL = 3; } Corpus corpus = 4; }
なお、reserved
キーワードも前述の通りに使うことができます。
repeated
repeated
でリストを定義できます。
message SearchResponse { repeated Result results = 1; } message Result { string url = 1; string title = 2; repeated string snippets = 3; }
map
map
でマップを定義できます。
map<string, Project> projects = 3;
map
は repeated
で修飾することはできません。
oneof
たくさんのフィールドがあり、その内の 1 つだけに値が設定される場合は oneof
を使うことでメモリを節約することができます。
message SampleMessage { oneof test_oneof { string name = 4; SubMessage sub_message = 9; } }
proto3 で Optional を表す代替として oneof を使うことができます。
以下のようにフィールドが 1 つの oneof
を定義します。
message Request { oneof option { int64 option_value = 1; } }
以下のように Optional を模倣することができます。
Request.OptionCase optionCase = request.getOptionCase(); OptionCase optionNotSet = OPTION_NOT_SET; if (optionNotSet.equals(optionCase)){ // value not set } else { // value set }
デフォルト値
やり取りするメッセージに特定の要素が含まれていない場合、そのフィールドのデフォルト値が適用されます。
- 文字列:空の文字列
- バイト:空のバイトです。
- bool:false
- 数値型:ゼロ
- enums:最初に定義されたフィールド番号 0 の enum値
- メッセージフィールド:設定されない(言語に依存)
- 繰り返しフィールド:空
パッケージ
名前のコンフリクトを防ぐために package
キーワードでパッケージを定義することができます。
package foo.bar; message Open { ... }
以下のようにドットで連結して参照することができます。
foo.bar.Open open = 1;
パッケージは、生成されたコードの言語で扱いがことなります。
Go や Java はそのままパッケージとして扱われます(option go_package
や option java_package
でソース上のパッケージを上書することができます)。
インポート
他の .proto
の定義をインポートするには するには、import
キーワードで他の .proto
ファイルを指定します。
import "myproject/other_protos.proto";
インポートすると、この .proto
内でのみ インポートした定義を利用することができます。
さらに外側の .proto
までインポートした定義を公開するには以下のように public
キーワードを指定します。
import public "myproject/other_protos.proto";
これによりインポートした定義を他の .proto
に推移させることができます。
オプション
.proto
ファイルには option
キーワードで注釈をつけることができます。
生成されたJavaクラスに使用するパッケージを指定するには以下のようにします。
option java_package = "com.example.foo";
デフォルトではパッケージのクラスの内部クラスとしてメッセージやサービスが定義されますが、以下の指定をすることで、内部クラスではなく通常のクラスとしてコード生成されます。
option java_multiple_files = true;
生成する外部クラス名を指定するには以下のオプションを設定します。
option java_outer_classname = "Ponycopter";
コンパイラオプション
protoc
コンパイラにて .proto
ファイルからコード生成を行います。
protoc --proto_path = IMPORT_PATH --cpp_out = DST_DIR --java_out = DST_DIR --python_out = DST_DIR --go_out = DST_DIR --ruby_out = DST_DIR --objc_out = DST_DIR --csharp_out = DST_DIR path / to / file .proto
IMPORT_PATH には .proto
を探すディレクトリを指定します(省略すると現在のディレクトリ)。
--proto_path
は -I
のように省略形を指定することもできます。
DST_DIR は出力先のディレクトリを指定します。それぞれ出力先の言語を並べて指定することができます。
--cpp_out
で C++ コードを生成--java_out
で Java コードを生成--python_out
で Python コードを生成--go_out
で Go コードを生成--ruby_out
で Ruby コードを生成--objc_out
で Objective-C コードを生成--csharp_out
で C#コードを生成--php_out
で PHP コードを生成