Protocol Buffer: Basics Go (Tutorial)

# Protocol Buffer: Basic Go

このチュートリアルはGoプログラマにprotocol buffersの使い方を紹介します。
使われるprotocol buffersのバージョンはproto3です。

簡単なサンプルアプリケーションの作成によって

* **.protoファイル内でのmessageの定義の仕方**
* **protocol buffer compilerの使い方**
* **Go protocol buffer APIを用いたmessageの読み書きの仕方**

を紹介します。

protocol bufferの詳細な情報を知りたい場合は以下へどうぞ
[Protocol Buffer Language Guide](https://developers.google.com/protocol-buffers/docs/proto3)
[Go API Reference](https://godoc.org/github.com/golang/protobuf/proto)
[Go Generated Code Guide](https://developers.google.com/protocol-buffers/docs/reference/go-generated)
[Encoding Reference](https://developers.google.com/protocol-buffers/docs/encoding)

## Why use protocol buffers?

ここで作るサンプルアプリケーションは、連絡先情報の書き込み、読み込みをファイル？との間でできるような簡単な連絡帳アプリケーションです。

それぞれの連絡先情報は
* 名前
* ID
* Email
* 電話番号
の情報を持っています。

これらのデータをシリアライズするには様々な方法があり、例えば
* goのパッケージ[gob](https://golang.org/pkg/encoding/gob/)を使う
* XMLを使う
などがあります。

Protocol buffersはこのシリアライズの問題に対して**柔軟で**, **効率的**, **自動的** な解決策を示すことができます。
`.proto`ファイルに保存したいデータを記述するとProtocol bufferのコンパイラは効率的なバイナリ形式でProtocol Bufferデータの自動エンコーディングと解析を実装します。

さらに、Protocol Bufferは以前のフォーマットで符号化されたデータを読み取れるようにフォーマットを拡張していく考え方に元付いて作られています。

## Defining your protocol format
サンプルアプリケーションを作っていきましょう。

まず、`.proto`ファイルを作る必要があります。
.protoファイルにはシリアライズしたいデータを追加していきます。
このサンプルでは`addressbook.proto`を作りましょう

`.proto`ファイルはパッケージの宣言から始まります、これは異なるプロジェクト間のネームスペースの競合を防ぐのに役立ちます。

```
syntax = "proto3";   // 使うバージョンの指定
package tutorial     // パッケージの宣言
```
パッケージ名は`go_package`を指定しない限り、goパッケージとして解釈されます。
go_packageを使用する際もネームスペースの競合が起きないようにpackageを宣言する必要があります。


次にメッセージを定義します。
メッセージは型付きのフィールドを含む集合体です。
`bool`,`int32`,`float`,`double`,`string`など多くの標準的なデータ型をフィールドの型として指定することができます。
他のメッセージタイプをフィールドタイプとして宣言し、メッセージに構造を持たせることも可能です

```.proto
syntax = "proto3";
package tutorial;


message Person {
  string name = 1;
  int32 id = 2;
  string email = 3;

  enum PhoneType {
    MOBILE = 0;
    HOME = 1;
    WORK = 2;
  }

  message PhoneNumber {
    string number = 1;
    PhoneType type = 2;
  }

  repeated PhoneNumber phones = 4;
}

message AddressBook {
  repeated Person people = 1;
}
```
上記のサンプルでは`Person message`には`PhoneNumber message`が含まれ、`AddressBook message`には`Person message`が含まれています。
上記のようにネストされた他のメッセージもフィールドタイプとして定義することができます。
さらに、列挙型を定義する事も可能です。

各要素に書かれている『= 1』『= 2』などはフィールドがバイナリで使用する際に一意のタグを識別する為に必要です
もしフィールドの値がセットされていなかった時にはデフォルト(数値型： 0, String: "", bool: false, )が使用されます

フィールドが`repeated`の場合、フィールドを任意の回数繰り返す事ができます。
繰り返される値の順序はProtocol bufferに保存されます。
`repeated`フィールドは動的サイズの配列と考えることができます。

`.proto`ファイルの完璧なガイドを見たい場合は次のサイトを参照して見てください。
[Protocol Buffer Language Guide](https://developers.google.com/protocol-buffers/docs/proto3)


## Compiling your protocol buffers

次は先ほど定義した`.proto`ファイルをコンパイルさせ定義したクラスなどを生成させていきます。

これには`protoc`コマンドを使います。

1. protocコマンドがインストールされていない場合はこちらよりダウンロードしてください。
[Download the package](https://developers.google.com/protocol-buffers/docs/downloads.html)

2. 次のコマンドを入力してGoのprotocol buffersプラグインをインストールしてください。

```shell
go get -u github.com/golang/protobuf/protoc-gen-go
```

3. コンパイラを実行します。 ソースコードディレクトリ(指定しなかった場合はカレントディレクトリ)、宛先ディレクトリ(生成されたコードをどこに置くかを指定します。 多くの場合$SRC_DIRと同じです)の指定と`.proto`ファイルのパスの指定を行います。

```shell
protoc -I=$SRC_DIR --go_out=$DST_DIR $SRC_DIR/addressbook.proto
```

ex
|
-addressbook.proto

の場合は

```shell
protoc -I=./ --go_out=./ addressbook.proto
```
のようになります。

## The Protocol Buffer API

生成された`addressbook.pb.go`によって
* Peopleフィールドを含んだAddressBook
* Name, Id, Email, Phonesを含んだPerson
* Number, Typeを含んだPerson_PhoneNumber
* enum型のPerson.PhoneTypeを含んだ`Person_PhoneType`
のような便利な型を使えるようになります。

ここで何を作られているのか詳しく知りたい場合は[Go Generated Code guide](https://developers.google.com/protocol-buffers/docs/reference/go-generated)を呼んでください。

Personインスタンス作成の例は次のような感じです。(Go)

```.go
p := pb.Person{
        Id:    1234,
        Name:  "John Doe",
        Email: "jdoe@example.com",
        Phones: []*pb.Person_PhoneNumber{
                {Number: "555-4321", Type: pb.Person_HOME},
        },
}
```

## Writing a Message

protocol buffersを使う目的はデータのシリアライズでした。
Goではprotoライブラリの[Marshal](https://godoc.org/github.com/golang/protobuf/proto#Marshal)関数を使うことによりデータをシリアライズすることができます。
`proto.Marshal`を呼ぶとシリアライズされたprotocol bufferが帰ってきます。

例


```go
book := &pb.AddressBook{}
// ...

// Write the new address book back to disk.
out, err := proto.Marshal(book)
if err != nil {
        log.Fatalln("Failed to encode address book:", err)
}
if err := ioutil.WriteFile(fname, out, 0644); err != nil {
        log.Fatalln("Failed to write address book:", err)
}
```

## Reading a Message

エンコードされたメッセージをパースするにはprotoライブラリの[Unmarshal](https://godoc.org/github.com/golang/protobuf/proto#Unmarshal)関数を使います。
これを呼び出すとbufのデータをprotocol bufferとして解析し、結果をpbに格納することができます。

例

```.go
// Read the existing address book.
in, err := ioutil.ReadFile(fname)
if err != nil {
        log.Fatalln("Error reading file:", err)
}
book := &pb.AddressBook{}
if err := proto.Unmarshal(in, book); err != nil {
        log.Fatalln("Failed to parse address book:", err)
}
```

これでチュートリアルは完了です
お疲れ様でした。

さらに詳しい情報を知りたい方は次のリンクを見てみてください。
[Protocol Buffer Language Guide](https://developers.google.com/protocol-buffers/docs/proto3)