色々Goで書いてみてやはりガードオブジェクトが欲しい、と思うことがよくある。一時的に何かの値を有効にしたり、かならず解放・リセット処理を行いたい場合のイディオムだ。これでいいのかわからないのだけど、とりあえず現時点で自分がやっていることをメモしておく。

Goにはdeferという仕組みがあって、関数の最後に必ずこれを実行してくれる。だがこれをオブジェクト構造体 につける方法はない。もちろん、構造体に対する関数呼び出しをdeferすることで同じ事ができるんだけど、そうするとどの関数を呼び出すのかをいちいち覚えていないといけない。一応runtime.SetFinalizer()というものはあるんだけど、これはいつ処理が走るのかわからないし、複数のオブジェクトやリソースが絡んでいる時にどの順番で処理が走るかもわからない。

ということはやはりdefer() を駆使するべきだろう。ということで自分は以下のような方法を使うことで今のところ落ち着いている。

func GuardLike () func() {
... 色々処理 ...
return func() {
... 解放処理 ...
}
}

func main() {
closer := GuardLike()
defer closer()
}  
これであればGuardLike()の中でどんな処理が行われていようと呼び出し側で気にすることなく関数をdeferから呼び出す、ということだけ覚えておけばよい。これでいいのかわからないので「こっちのほうがいいよ」という意見があれば教えて欲しい。

ちなみにPerl等のeval { ... }に相当するものを書きたい時も自分は関数でラップした上でdefer + recoverを使うなどしているので、goは結構このdeferの使い方をうまくすることで色々楽ができそうな気がする。

あとトランザクションのロールバックのような処理はなんか明示的に書いたほうがいいのかと思って今は明示的にTxnRollback()というラッパー関数を呼び出すようにしている。まだこのあたり流儀を統一できてない。