Goでos.Exit()
とdefer f()
を両方使う場合を何度も調べている気がするので覚書。
おなじ関数内でこれらを使うと、defer
が実行されない。別関数に分離すべき。
具体例
os.Exit()はDefer functionの実行を待たない - harukasan | Qiita
でも書かれているが
package main
import "os"
func test() {
println("hello in test.")
}
func main() {
println("hello in main.")
defer test()
println("pre-exit in main.")
os.Exit(0)
}
/** OUTPUT **
hello in main.
pre-exit in main. <-- defer test()が実行されていないで終わる
*/
ということが起こる。
例えばファイルのクローズなどの処理をdefer
に書き、おなじ関数内でos.Exit()
すると意図した終了処理が行われない。
公式ドキュメントによると、
Go言語のdeferステートメントは、deferを実行した関数がリターンする直前に、指定した関数の呼び出しが行われるようにスケジューリングします。
とのことなので、関数を分けてしまえば良い。
package main
import "os"
func test() {
defer func() {
println("defer in test.")
}()
println("hello in test.")
}
func main() {
println("hello in main.")
test()
println("pre-exit in main.")
os.Exit(0)
}
/** OUTPUT **
hello in main.
hello in test.
defer in test.
pre-exit in main.
*/
よくあるコマンドコンソールアプリの構造だと以下のような感じにする。
github.com/umanoda/hoge
├── cmd
│ └── hoge
│ └── main.go : package main
└── hoge.go : package hoge
github.com/umanoda/hoge/hoge.go
package hoge
type Hoge struct{
:
}
func New() Hoge{
h := Hoge{../* etc.. */..}
return h
}
// errorインターフェースの実装
func (h *Hoge) Error() string{
return "hogeeeeeeeee!!"
}
func (h *Hoge) Run() (*Hoge, error){
/*
: 処理
*/
defer func(){...}() //クローズなどの処理
// 正常終了
return h, nil
// 異常終了
return h, h
}
github.com/umanoda/hoge/cmd/hoge/main.go
package main
import (
"fmt"
"os"
"github.com/umanoda/hoge/hoge"
)
func main(){
h = hoge.New()
_, err := h.Run()
if err != nil {
// 異常終了
fmt.Println("error: ", err)
os.Exit(1) // h.ErrorCode()を実装するとかはお好きに
}
os.Exit(0) // 正常終了
}
検証環境
$ go version
go version go1.6.2 linux/amd64