简单的说就是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