Goにおいてstruct{}型はフィールドを持たない構造体であり、0バイトのメモリしか占有しません。この特性は、何かの存在を示すことが重要であり、データは必要ない場合にリソース消費を最小限に抑えるために利用されます。たとえば、集合の実装、シグナリング構造体、またはイベント用のチャネルに使用されます。
集合の使用例:
mySet := make(map[string]struct{}) mySet["foo"] = struct{}{} if _, ok := mySet["foo"]; ok { fmt.Println("fooはmySetに存在します") }
struct{}は、キーの存在を示すために値として使用されます。map[string]boolとは異なり、struct{}を使用する方がメモリ効率が良いです。シグナリングチャネル:
done := make(chan struct{}) // ゴルーチンは終了信号を待機します <-done
集合の実装におけるmap[string]struct{}とmap[string]boolの違いは何ですか?なぜmap[string]struct{}の方が好まれ、欠点はありますか?
回答:
map[string]struct{}は値に対して0バイトを使用し、最もコンパクトなオプションです。特にデータが多数存在する場合、メモリが節約されます。map[string]boolは値に対して1バイトを必要とします(内部ではアライメントのためにもっとメモリを占有する可能性があります)。map[string]struct{}の欠点は、もし真偽値が必要な場合に、すぐにすべての真の値のリストを取得できないことです。結局のところ、キーを通じての調査が必要です。例:
set := make(map[string]struct{}) set["Alice"] = struct{}{} _, exists := set["Alice"] // true flags := make(map[string]bool) flags["Alice"] = true _, exists := flags["Alice"] // true
逸話
ユニークな識別子を保持するプロジェクトでmap[string]boolを使用した結果、データが増えるにつれてメモリ消費が著しく増加し、map[string]struct{}のオプションと比べて数百メガバイトになった。struct{}に切り替えたことで、メモリ消費が2倍以上減少した。
逸話
新人が
chan boolを通じてゴルーチンの終了を通知した。多くのゴルーチンの場合、値の送信が冗長であり、trueかfalseのいずれが来たか分析されなかった。chan struct{}に置き換えたことで、アーキテクチャの不正確さが示され、コードが簡素化された。
逸話
ライブラリではmapを使って集合を作成し、値としてstringを使用していた。これはあまりにもメモリを消費していた。コードレビューの後、map[タイプ]struct{}に変更された。メモリプロフィールの分析は、負荷テスト中にアプリケーションがOOMでクラッシュしたときにエラーが見つかった。