手続き的に main 内で初期化→defer 後処理→メイン処理→エラー検知したら exit 1 で終了みたいなことをやりがちだけど, 意図と違う挙動になることがあるので注意が必要というやつ。

os.Exit なし版 main 関数の終了時 defer 処理が走る

package main
import "fmt"
func main(){
    fmt.Println("start")
    defer func() {
        fmt.Println("defer") 
    }()
    fmt.Println("end")
}
// output:
// start
// end
// defer

os.Exit あり版

package main
import (
    "fmt"
    "os"
)
func main(){
    fmt.Println("start")
    defer func() {
        fmt.Println("defer") 
    }()
    os.Exit(1)
    fmt.Println("end")
}
// output:
// start
// ...
// ...
// echo $? -> 1

終了処理でよく見る err をハンドリングして log.Fatal というやつ log.Fatal も中では os.Exit してるので同じ

// Fatal is equivalent to Print() followed by a call to os.Exit(1).
func Fatal(v ...interface{}) {
	std.Output(2, fmt.Sprint(v...))
	os.Exit(1)
}

回避は関数を分ける必要がある

package main
import (
    "fmt"
    "os"
)
func main(){
    run()
    os.Exit(1)
}

func run() {
    fmt.Println("start")
    defer func() {
        fmt.Println("defer") 
    }()
    fmt.Println("end")
}
// output:
// start
// end
// defer