Protocol Buffersのpackageの名前解決ルールを調べました。 このブログはproto3のドキュメントベースで書いています。
protobufのpackageについて
protobufでは、messageなどの定義名が衝突することを防ぐことを目的として、名前空間を分離できる package
と言う機構が提供されています。
説明を簡略化するために、本家のドキュメントを引用します。
Packages
You can add an optional package specifier to a .proto file to prevent name clashes between protocol message types.
package foo.bar; message Open { ... }
You can then use the package specifier when defining fields of your message type:
message Foo { ... foo.bar.Open open = 1; ... }
From: Language Guide (proto3) | Protocol Buffers | Google Developers
上記のように、importした側のprotoで、 foo.bar.Open
と言った形で別packageのmessageを参照することが出来ます。
protobufの名前解決ルールについて
protobufのPackage名ベースでの名前解決は、初めに innermost scope
から検索を開始する形で行われます。例としては、 foo.bar package
から X
messageの検索を始め、foo.bar package
内に見付からなければ、次は foo package
内に無いか探しに行くといった感じです。
https://developers.google.com/protocol-buffers/docs/proto3#packages_and_name_resolution
名前解決の具体例
foo foo.bar foo.baz
の3 packageがあった時、
- foo.Fooは、foo.bar および foo.bazから、
.foo.Foo
,foo.Foo
, またはFoo
としてアクセス出来ます。 - foo.bar.Barは、foo.bazから、
.foo.bar.Bar
,foo.bar.Bar
, またはbar.Bar
としてアクセス出来ます。
後者の方が若干ややこしいのですが、 innermost scope
での検索なので、bar
はスコープに入っておらず省略することが出来ません。
実例のProtoを貼っておきます。
foo/foo.proto
syntax = "proto3"; package foo; message Foo { }
foo/bar/bar.proto
syntax = "proto3"; package foo.bar; import "foo.proto"; message Bar { foo.Foo foo1 = 1; Foo foo2 = 2; }
foo/baz/baz.proto
syntax = "proto3"; package foo.baz; import "foo.proto"; import "bar/bar.proto"; message Baz { foo.Foo foo1 = 1; Foo foo2 = 2; // OK foo.bar.Bar bar1 = 3; bar.Bar bar2 = 4; // Bar bar3 = 5; // NG }
名前が衝突した時の挙動
前述した通り、packageベースの名前解決は innermost
なので、最も内側のスコープで、importしたmessageと同じ名前のmessageを再定義することが出来ます。
上記の foo.baz
packageの例で言うと、次のようなProtoが書けます。
foo/baz/baz.proto
syntax = "proto3"; package foo.baz; import "foo.proto"; import "bar/bar.proto"; message Foo { string msg = 1; } message Baz { foo.Foo foo1 = 1; Foo foo2 = 2; // Redeclared in baz.proto foo.bar.Bar bar1 = 3; bar.Bar bar2 = 4; // Bar bar3 = 5; // NG }
これを実際にコンパイルしたところ、 foo1
と foo2
で別々の型として扱われていることがちゃんと確認できました。
til/baz.pb.go at 68cce142b9e0b9a336fe65432238fea18b8206ce · syumai/til · GitHub
ひとまず今回確認したかったルールはここまでで、それはそうと言う内容ですが、ちゃんと説明できる程度に理解できたのでスッキリしました。 Proto周りのツールを連休中作っているので、完成したらまたブログで紹介すると思います! それでは皆さんよい連休を👋