protobufで0 byteをデコードする

Language Guideに以下のようにフィールドに値がセットされていない場合はdefault valueが使われることが書かれています。

When a message is parsed, if the encoded message does not contain a particular singular element, the corresponding field in the parsed object is set to the default value for that field.

ということは何も書かれていない(0 byteの)バリナリをパースしようとすると、すべてのフィールドがdefault valueとなるはずなので試してみました。

パースする.proto

以下のような.protoを用意します。

syntax = "proto3";
package blank;

message User {
  int32 id = 1;
  string name = 2;
  fixed64 age = 3;
  Contact contact = 4;
}

message Contact {
  string phone = 1;
  string email = 2;
}

protocします。

❯ protoc -I=blank/ --go_out=blank/ blank.proto

パースする

0 byteの入力としてin := []byte{}を使います。 inUserにパースし、各フィールドを標準出力して、default valueになっているか確認します。

package main

import (
    "fmt"
    "log"

    pb "github.com/cipepser/protobuf-sample/blank"
    "github.com/golang/protobuf/proto"
)

func main() {
    user := &pb.User{}
    in := []byte{}

    if err := proto.Unmarshal(in, user); err != nil {
        log.Fatal(err)
    }

    fmt.Println("ID: ", user.Id)
    fmt.Println("Name: ", user.Name)
    fmt.Println("Age: ", user.Age)
    fmt.Println("Contact: ", user.Contact)
 }

結果

実行結果は以下の通りです。

❯ go run BlankRead.go
ID:  0
Name:
Age:  0
Contact:  <nil>

ちゃんとdefault valueでパースできました。
ちなみに、上記の通りuser.Contactnilがdefault valueのため、PhoneEmailにアクセスしようとするとpanicになります。

fmt.Println("Phone: ", user.Contact.Phone)
// panic: runtime error: invalid memory address or nil pointer dereference

References