CやC++ではatexit関数で関数を登録しておくと、プログラムの終了時にその関数を自動的に走らせることができる。そういう機能はRubyやPythonにもある。
Goにはそういう機能はない。実装を忘れているのではなくて、意図的にそういう機能を持たせていないのだ。これについてIan Lance Taylorさんが大変説得力のある説明をしていた。
まず第一に、どんなプログラムでも任意の箇所でクラッシュしうるし、まったくバグのないプログラムでもいきなりkillで殺されたりマシンが電源断で落ちるということがある。従ってどんなプログラムも、突然終了させられたあとに、もう一度きちんと動くことができなければならない。つまりatexitはきれいに終了するための機能ということで、atexitが呼び出されないとうまく動かないプログラムというのはそもそも間違っているということになる。
大きなC++プログラムではたくさんのグローバルなデストラクタやatexitが走ることになる。そしてそれはプログラムのサイズに応じて、時に驚くほど長い時間を要することがある。プロセスの終了を待っている間はなにもすることはできない ―― ただ終了をじっと待つだけだ。しかもその終了処理は、本当はやらなくても再起動にはなんの支障も及ぼさないことをやっているのだ。
C++コミュニティはこの問題をよく認識していて、それを解決するために、C++11でstd::quick_exitというのを導入した。これは終了処理を走らせないでプロセスを即座に終了するための関数だ。しかし終了処理をそれでも走らせたいというひとたちのために、結局std::at_quick_exitというのも同時に導入された。こうなると冗談めいた状況になっていると言わざるをえない。
そういう状況に陥らないようにするため、Goでは最初からatexitが用意されていないし、グローバルなデストラクタも用意されていない。os.Exitはdeferも実行せずに即座に終了する。このデザインはときどき不便なことも引き起こすが(atexitが確かに便利というのは否定しない)、あるのとないのでは、ないほうがよいというのがGoのデザイン上の選択なのだ。