最後に追記あり
どの 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 っぽいのかは疑問の残るところ。