大家都了解C++有构造函数和析构函数,加之每一个栈对象都有其严格的作用或,离开则自动调用其析构函数,以此来保证释放其掌控的资源,如:内存,文件,socket,数据库链接等, 其它一些语言提供类似的机制,如: init, deinit等, 那么对于追求大道至简的golang, 她没有提供构造函数和析构函数的概念, 但是她也不可避免要处理资源的自动释放问题, 所以其提供了defer, 如: defer f() 用于延迟调用f(), 当此语句所在函数执行完(return执行完)后,开始以“后进先出”的顺序执行defer语句。但是defer不是一定会被执行的,我简单归总了一下,怕我以后忘记, 见测试代码:
package main import ( "fmt" //"log" //"os" ) func main() { fmt.Println("test\n") if true { fmt.Println("add defer") defer fmt.Println("defer run!!") //虽然在if的小block中, 但是defer只会到函数执行完时才执行,而不是在离开if作用域时执行。 } fmt.Println("test end\n") //1. defer不会执行了. //log.Fatal() //os.Exit(1) //2. defer会照常执行。 //log.Panic() //panic(nil) //return //reach the end of the function normally. }
通常我们只把os.Exit用于test case代码中, 生产代码中很少用,可能有用它的理由就是程序退出时向操作系统报告状态码,但是会中断defer的执行,为了使资源被正确释放
掉, 我们可以采用以下代码的处理方式, 把业务逻辑代码单独封装在一个函数中, 在退出这个函数时,注意只是在函数执行完return以后,与作用域无关 一切defer皆自动执行完,不用再担心os.Exit()了,见代码:
func main() { if err := run(); err != nil { fmt.Fprintf(os.Stderr, "error: %v\n", err) os.Exit(1) //当执行此行时, run()早已执行完退出,其中defer早已执行完;但与os.Exit同一上下文的代码中就不要用defer了, 因为会被中断,不再执行。 } } func run() error { err := something() if err != nil { return err } // etc, 这是程序用defer清理资源的最后一条防线。 }
参考链接:
http://stackoverflow.com/questions/18963984/exit-with-error-code-in-go
http://stackoverflow.com/questions/28472922/when-to-use-os-exit-and-panic-golang
注意: 此文章只是我个人笔记, 如有错漏,请一定指正, 共同学习, 我的邮箱: htyu_0203_39@sina.com
有疑问加站长微信联系(非本文作者)