便利メソッド(util)系を Static Method としてまとめる


最後に追記あり

どの Struct にも属さない(コンテキストを持たない)便利関数をどこかにまとめる時。
サブディレクトリとして持って各ファイルで import してもいいんだけど、そこまでする必要は無いので、同じプロジェクト内の util.go に書いていた。
ここに書いた関数は、プロジェクト内では共有される、いわゆるグローバルなアクセスができるので、どのファイルからもアクセスできる。こんな感じ。

// util.go
func AddPrefix(header http.Header) http.Header {
  // snip
}

func RemovePrefix(header http.Header) http.Header {
  // snip
}

これらは struct に属していないため Godoc 上で最初にまとめて表示される。なぜなら Godoc ではどのファイルにあるかは表示されないから。

これだと、 ListenAndServe() とか Dial() みたいに、関数として定義するものがあると、 Util みたいにどうでもいいものと混ざって見づらいという問題がある。上の場合は HandleTLSConnection() は重要だけど、他はどうでもいい。

どうでもいいなら、関数名を小文字にすればいいのだが、ここから消えてほしくはないし、外部にも公開したい。

そこで、 util.go にあるものは「Util であること」を Godoc 上でわかりやすくしたい。
なので、あえて struct に属させてみる。
しかし、使うたびにいちいち new() するのも面倒なので、 util.go 上で new したものをグローバルに載せる。これで今までの関数呼び出しを頭に util.Xxx() とするだけで同じように使える。

var util = Util{}

type Util struct{}

func (u Util) AddPrefix(header http.Header) http.Header {
  // snip
}

func (u Util) RemovePrefix(header http.Header) http.Header {
  // snip
}

Godoc はこうなる。いい感じ。

これでこのパッケージを import した側も package.util.Xxx() で呼べるはずだし、いいのかなぁと、いうのをやってるんだけどどうだろう。
ドキュメントを読んでない人は util を new() するかもしれないけど、そこはまあしょうがないかなぁ。

追記

interface にしなかった理由

たまーに const とか var も持ちたくなることがあったからです(書いてなかったです、すいません)。関数だけなら interface にして方が確かにいいですね。

サブパッケージにしなかった理由

サブパッケージにすると、 import が増えるのと、各ファイルで import が必要になるのと、 GoDoc 上では別のページになるからですね。今回のように数個の関数だけだとわざわざ掘るのも面倒だなと。
もし ioutil ほど大きければサブパッケージの方が良いのは確かです。
ちなみに crypto/util.go とかもあるので、サブパッケージの方が必ず Go っぽいのかは疑問の残るところ。