简单的说就是Go中用defer关键字来修饰函数起到延迟执行的效果。
defer 表达式会被放入一个类似于栈( stack )的结构,所以调用的顺序是先进后出/后进先出的
package main import ( "fmt" ) func main() { defer fmt.Print(1) defer fmt.Print(2) defer fmt.Print(3) defer fmt.Print(4) } 执行结果: 4 3 2 1
因此这段代码输出的结果是 4321 而不是 1234 。
package main import ( "fmt" "time" ) func main() { c := 2 defer P(c) time.Sleep(5e9) c = 5 fmt.Println("main ", c) } func P(c int) { fmt.Println("defer", c) fmt.Println("P ", c) } 执行结果: main 5 defer 2 P 2
package main import ( "fmt" "time" ) func main() { defer P(time.Now()) time.Sleep(5e9) fmt.Println("main ", time.Now()) } func P(t time.Time) { fmt.Println("defer", t) fmt.Println("P ", time.Now()) } 执行结果: main 2018-07-25 16:42:19.228832898 +0800 HKT m=+5.003306219 defer 2018-07-25 16:42:14.226136368 +0800 HKT m=+0.000609813 P 2018-07-25 16:42:19.229130521 +0800 HKT m=+5.003603820
匿名返回值的情况
package main import ( "fmt" ) func main() { fmt.Println("a return:", a()) } func a() int { var i int defer func() { i++ fmt.Println("a defer1:", i) }() defer func() { i++ fmt.Println("a defer2:", i) }() return i } 执行结果: a defer2: 1 a defer1: 2 a return: 0
有名返回值的情况
package main import ( "fmt" ) func main() { fmt.Println("a return:", a()) } func a() (i int) { defer func() { i++ fmt.Println("a defer1:", i) }() defer func() { i++ fmt.Println("a defer2:", i) }() defer func() { i++ fmt.Println("a defer3:", i) }() return i //或者等价于return } 执行结果: a defer3: 1 a defer2: 2 a defer1: 3 a return: 3
package main import ( "fmt" ) func main() { c:=c() fmt.Println("c return:", *c, c) func c() *int { var i int defer func() { i++ fmt.Println("c defer1:", i, &i) }() defer func() { i++ fmt.Println("c defer2:", i, &i) }() defer func() { i++ fmt.Println("c defer3:", i, &i) }() return &i } 执行结果: c defer3: 1 0xc420012088 c defer2: 2 0xc420012088 c defer1: 3 0xc420012088 c return: 3 0xc420012088
虽然 c()int 的返回值没有被提前声明,但是由于 c()int 的返回值是指针变量,那么在 return 将变量 i 的地址赋给返回值后,defer 再次修改了 i 在内存中的实际值,因此 return 调用 RET 退出函数时返回值虽然依旧是原来的指针地址,但是其指向的内存实际值已经被成功修改了
defer 只对当前协程有效(main 可以看作是主协程)
package main import ( "errors" "fmt" "time" ) func main() { e := errors.New("error") fmt.Println(e) defer fmt.Println("defer") go func() { panic(e) }() // 会导致 defer 不会执行 time.Sleep(1e9) fmt.Println("over.") } 执行结果: error panic: error goroutine 5 [running]: main.main.func1(0x51b120, 0xc42000e1d0) /root/workspace/defer6.go:13 +0x3e created by main.main /root/workspace/defer6.go:13 +0x145 exit status
当任意一条(主)协程发生 panic 时,会执行当前协程中 panic之前已声明的 defer
package main import ( "errors" "fmt" "time" ) func main() { e := errors.New("error") fmt.Println(e) defer fmt.Println("defer") panic(e) // defer 会执行 time.Sleep(1e9) fmt.Println("over.") } 执行结果: error defer panic: error goroutine 1 [running]: main.main() /root/workspace/defer6.go:13 +0x178 exit status 2
在发生 panic 的(主)协程中,如果没有一个 defer 调用 recover()进行恢复,则会在执行完最后一个已声明的 defer 后,引发整个进程崩溃
package main import ( "errors" "fmt" "time" ) func main() { e := errors.New("error") fmt.Println(e) panic(e) // defer 不会执行 defer fmt.Println("defer") time.Sleep(1e9) fmt.Println("over.") } 执行结果: error panic: error goroutine 1 [running]: main.main() /root/workspace/defer6.go:12 +0xfb exit status 2
主动调用 os.Exit(int) 退出进程时,defer 将不再被执行
package main import ( "errors" "fmt" "time" "os" ) func main() { e := errors.New("error") fmt.Println(e) os.Exit(1) // defer 不会执行 defer fmt.Println("defer") time.Sleep(1e9) fmt.Println("over.") } 执行结果: error exit status 1
package main import ( "errors" "fmt" "time" "os" ) func main() { e := errors.New("error") fmt.Println(e) defer fmt.Println("defer") time.Sleep(1e9) fmt.Println("over.") os.Exit(1) // defer 不会执行 } 执行结果: error over. exit status 1