この記事の内容は以下のバージョンで作りました。
> go version
go version go1.13 windows/amd6
きっかけ
- ちょっとしたgoのコードを書いているときに、「リソースの開放が面倒だなぁ」とおもった。
- .NETだと、usingステートメントですごくすっきりかけるから、似たようなものを作りたい。
通常のgoの場合
// 何らかのリソースを取得する
resource, err := hogehoge.GetResource()
// エラーがあるかどうか調べてちょめちょめする
if err != nil {
// ちょめちょめ
}
// 解放忘れがないように、deferを定義
defer resource.Close()
// ようやく本来やりたい処理
みたいな感じになる。本来やりたい処理を書き始めるまでいつまでかかるんだ・・・
という感じ
今回作ったもの
type IDispose interface {
open() error
dispose()
}
func Using(disposable IDispose, fn func(resource interface{}) error) (err error) {
if err = disposable.open(); err != nil {
return err
}
defer disposable.dispose()
if err = fn(disposable); err != nil {
return err
}
return nil
}
IDisposeな構造体と関数を受け取り、Open/実行/Closeまでを自動的にやってくれるやつ。
使い方
IDisposeな構造体を用意
type DisposableStruct struct {
hogeResouce *hoge.HogeResource
}
func (s *DisposableStruct) open() error {
return nil
}
func (s *DisposableStruct) dispose() {
// リソースを破棄する処理
s.hogeResouce.Close()
}
実行部
err := Using(&DisposableStruct{hogeResouce: nil}, func(r interface{}) error {
// castする必要がある。イケてない部分1
hoge := r.(*DisposableStruct)
// ここに本来やりたい処理を書く
// 戻り値はエラーのみ。イケてない部分2
return nil
})
最後に
- ジェネリクスが使えれば、もっとかっこよくかけるんだけど・・・
- golangでこんな無駄なことしてんじゃねぇよみたいに言われるかもしれないけど、気にしない。
- もっといい感じの実装がある場合はコメント欄で指摘をお待ちしております!
- 実際にはステートメントではなくただの関数です(タイトル詐欺ですまんな)