golangでデストラクタ的なことをする

  • 18
    いいね
  • 0
    コメント
この記事は最終更新日から1年以上が経過しています。

golangはstructにデストラクタ的なものを定義することは出来ないが、インスタンスがGCに拾われる時に任意の処理をさせることはできる。

具体的方法

runtimeパッケージのSetFinalizer()でfinalizer関数を設定できる。いわゆるデストラクタのようにstructの宣言に付けられるわけではなくて、インスタンスごとに設定しなければならない。
# なのでデストラクタではない

createInstance()でfinalizer関数を設定している。runtime.SetFinalizerには対象のインスタンスの参照とfinalizerとして設定する関数を渡す。

partial
func finalizer(m *string) {
        fmt.Println("finalize for ->", *m)
        return
}

func createInstance() {
        x := "hello"
        runtime.SetFinalizer(&x, finalizer)
        return
}

func main() {
        createInstance()
        runtime.GC()
        time.Sleep(1 * time.Second)
        return
}
output
finalize for -> hello

finalizer関数は新しく立ち上げられたgoroutineで実行される。(このgoroutineが実行される時間をsleepで稼いでる)
finalizer()で出力させている文字列が出ていて、GCで回収されたタイミングで実行されていることが判る。

注意点

  • SetFinalizerを使用したインスタンスは、Finalizerが動作したタイミングではGCに回収されない。次回のGCで回収される。
  • finalizer関数は必ず実行されるわけではない。つまり、GCに回収されないケース(プロセスが終了する・GCが止まっている)は漏れる。
    • deferであれば確実に実行される

用途

あんまり綺麗じゃないし確実でもないので、積極的には使わないほうがいいような気がする。
個人的には、型じゃなくてインスタンスによって重要な動作が変わるのが、ヒジョーに気持ち悪い。
# 美観の問題かもだけど、deferで間に合うように書いたほうが読みやすい

とはいえcgoでc言語の関数をラップするとかの時とか、まぁどうしようもない事が時々ある。そんなときにだけ使いたい。