細かいことは置いといて、とりあえずProtocolBuffersを触ってみたい時の覚書

* タイトルの通り、自分が試した方法をまとめておく
* ProtocolBuffersとはなんぞや？に関しては公式とか色んな方がネットに情報上げてくれてるので割愛

# 環境構築

* ubuntu18.04
* Go1.14
* ディレクトリ構成

/home/user/
└── go/
　　　├── bin/
　　　├── pkg/
　　　└── src/
　　　　　　├── go.mod
　　　　　　├── go.sum
　　　　　　├── example.go
　　　　　　├── example.proto
　　　　　　└── pb/
　　　　　　　　　└── (protoファイルのコンパイル後のファイルをここに置く)

---
まずprotocのインストール（[ダウンロード先](https://github.com/protocolbuffers/protobuf/releases/)）

```bash:/home/user/
# protocのzipファイルをwget
$ wget https://github.com/protocolbuffers/protobuf/releases/download/v3.14.0/protoc-3.14.0-linux-x86_64.zip
# zipファイル解凍
$ unzip protoc-3.14.0-linux-x86_64.zip
# protocのバイナリをbin配下に移動
$ sudo mv bin/protoc /usr/local/bin/
# includeも移動（しておかないといけないらしい、参照するから）
$ sudo mv include/ /usr/local/
``` 
これでインストールされたはず

```bash:/home/user
# 確認
$ protoc --version
libprotoc 3.14.0
```
---
次にprotoc-gen-goのインストール

```bash
# インストール
$ go get -u google.golang.org/protobuf/cmd/protoc-gen-go
```
これで完了

```bash
# 確認
$ protoc-gen-go --version
protoc-gen-go v1.25.0
```
※ **Command 'protoc-gen-go' not found...** なんて表示されたら(僕の環境の場合)

```bash:/home/user/
# 下記をvim等で.profileに追加、PATHを通す
export PATH="$HOME/go/bin:$PATH"
# 反映
$ source .profile
```

# protoファイル作成
* message → フィールドというか値をまとめたもの
* enum → define定義のようなもの
* repeated → 配列
* = 番号 → タグのようなもの。連番で付ける(messageは1から。enumは0から)

※ option go_packageはなくても問題なさそうですが、WARNINGが出るので、こちら参考にさせていただきました
　 → [Protocol Buffersのgo_packageの;の仕様](https://nametake.github.io/posts/2020/05/24/protobuf-go-package-semicolon/)

```proto:go/src/example.proto
syntax = "proto3";
package example;

option go_package = ".;pb";

message User {
    int32 id = 1;
    string name = 2;

    enum AddressType {
        HOKKAIDO = 0;
        TOHOKU = 1;
        KANTO = 2;
        CHUBU = 3;
        KINKI = 4;
        CHUGOKU = 5;
        SHIKOKU = 6;
        KYUSYU = 7;
        OKINAWA = 8;
    }

    message Address {
        string area = 1;
        AddressType type = 2;
    }

    repeated Address addresses = 3;
}
```
# protoファイルのコンパイル
* 「-I」→ アプリケーションのソースコードが存在する場所
* 「--go_out」→ コンパイルで自動生成されるpb.goファイルの配置先

```bash:go/src/
# protocコマンドでコンパイル
$ protoc -I=. --go_out=./pb example.proto
```

# シリアライズとデシリアライズ
Goでシリアライズとデシリアライズを行う
※ コードはこちら参考にさせていただきました
　 → [Protocol Buffers 導入メモ Mac/Win](https://qiita.com/nzer0/items/7208c880693e63ca247a#4-%E8%A8%80%E8%AA%9E%E3%81%94%E3%81%A8%E3%81%AB%E3%82%B7%E3%83%AA%E3%82%A2%E3%83%A9%E3%82%A4%E3%82%BA%E3%83%87%E3%82%B7%E3%83%AA%E3%82%A2%E3%83%A9%E3%82%A4%E3%82%BA%E6%99%82%E3%81%AB%E4%B8%8A%E8%A8%98%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB%E3%82%92%E4%BD%BF%E7%94%A8)

```golang:go/src/example.go
package main

import (
	"fmt"
	pb "src/pb"

	"github.com/golang/protobuf/proto"
)

func main() {
	// シリアライズ
	obj := &pb.User{
		Id:   123,
		Name: "yuuzin217",
		Addresses: []*pb.User_Address{
			{
				Area: "Tokyo",
				Type: pb.User_KANTO,
			},
			{
				Area: "Kyoto",
				Type: pb.User_KINKI,
			},
		},
	}
	buff, err := proto.Marshal(obj)
	if err != nil {
		fmt.Println("シリアライズ失敗", err)
		return
	}
	fmt.Println("シリアライズ結果：", buff)

	// デシリアライズ
	parseResult := &pb.User{}
	err = proto.Unmarshal(buff, parseResult)
	if err != nil {
		fmt.Println("デシリアライズ失敗: ", err)
		return
	}
	fmt.Println("デシリアライズ結果 id: ", parseResult.Id)
	fmt.Println("デシリアライズ結果 name: ", parseResult.Name)
	fmt.Println("デシリアライズ結果 addresses: ", parseResult.Addresses[1].Area)
}
```
---
保存して実行

```bash:go/src/
# 実行
$ go run example.go
シリアライズ結果： [8 123 18 9 121 117 117 122 105 110 50 49 55 26 9 10 5 84 111 107 121 111 16 2 26 9 10 5 75 121 111 116 111 16 4]
デシリアライズ結果 id:  123
デシリアライズ結果 name:  yuuzin217
デシリアライズ結果 addresses:  Kyoto
```

# 参考
* [Protocol Buffer Basics: Go](https://developers.google.com/protocol-buffers/docs/gotutorial)
* [Language Guide (proto3)](https://developers.google.com/protocol-buffers/docs/proto3)
* [Protocol Buffers: ざっくりとした入門](https://qiita.com/kitauji/items/fdbd052c19dad28ab067)
* [Protocol Buffersのgo_packageの;の仕様](https://nametake.github.io/posts/2020/05/24/protobuf-go-package-semicolon/)
* [Protocol Buffers 導入メモ Mac/Win](https://qiita.com/nzer0/items/7208c880693e63ca247a)