defer的执行顺序:多个defer出现的时候,它是一个“栈”的关系,也就是先进后出。
defer与return谁先谁后:return语句先执行,defer语句后执行
package main
import "fmt"
func deferFunc() int {
fmt.Println("defer func called")
return 0
}
func returnFunc() int {
fmt.Println("return func called")
return 0
}
func returnAndDefer() int {
defer deferFunc()
return returnFunc()
}
func main() {
returnAndDefer()
}
函数的返回值会先初始化成零值
package main
import "fmt"
func DeferFunc1(i int) (t int) {
fmt.Println("DeferFunc1中的t = ", t)
return 2
}
func DeferFunc2(i int) (t int) {
return 2
}
func main() {
DeferFunc1(10)
fmt.Print("DeferFunc2中的t = ", DeferFunc2(10))
}
只要声明函数的返回值变量名称,就会在函数初始化时候为之赋值为零值,而且在函数体作用域可见。
- 对于值类型:布尔类型为
false
, 数值类型为0
,字符串为""
,数组和结构体会递归初始化其元素或字段,即其初始值取决于元素或字段。 - 对于引用类型: 均为
nil
,包括指针 pointer,函数 function,接口 interface,切片 slice,管道 channel,映射 map
有名函数返回值遇见defer情况
package main
import "fmt"
func returnButDefer() (t int) { //1.初始化0, 并且作用域为该函数全域
defer func() {
t = t * 10 //3.
}()
return 1 //2.
}
func main() {
fmt.Println(returnButDefer())
}
defer遇见panic
遇到panic时,执行defer。
如果没有遇到recover,执行完defer后,向stderr抛出panic信息。
遇到recover则停止panic,返回recover处继续往下执行。
A. defer遇见panic,但是并不recover(捕获异常)的情况
package main
import (
"fmt"
)
func main() {
defer_call()
fmt.Println("main 正常结束")
}
func defer_call() {
defer func() { fmt.Println("defer: panic 之前1") }()
defer func() { fmt.Println("defer: panic 之前2") }()
panic("异常内容") //触发defer出栈
defer func() { fmt.Println("defer: panic 之后,永远执行不到") }()
}
B. defer遇见panic,并recover(捕获异常)
package main
import (
"fmt"
)
func main() {
defer_call()
fmt.Println("main 正常结束")
}
func defer_call() {
defer func() {
fmt.Println("defer: panic 之前1, 捕获异常")
if err := recover(); err != nil {
fmt.Println(err)
}
}()
defer func() { fmt.Println("defer: panic 之前2, 不捕获") }()
panic("异常内容") //触发defer出栈
defer func() { fmt.Println("defer: panic 之后, 永远执行不到") }()
}
defer 最大的功能是 panic 后依然有效 所以defer可以保证你的一些资源一定会被关闭,从而避免一些异常出现的问题。要养成打开资源,下一行就是defer 关闭资源的习惯。
defer中包含panic
revover只会捕获最新的panic。
触发panic("panic")后defer顺序出栈执行,第一个被执行的defer中 会有panic("defer panic")异常语句,这个异常将会覆盖掉main中的异常panic("panic"),最后这个异常被第二个执行的defer捕获到。
package main
import (
"fmt"
)
func main() {
defer func() {
if err := recover(); err != nil {
fmt.Println(err)
} else {
fmt.Println("fatal")
}
}()
defer func() {
panic("defer panic")
}()
panic("panic")
}
defer下的函数参数包含子函数
package main
import "fmt"
func function(index int, value int) int {
fmt.Println(index)
return index
}
func main() {
defer function(1, function(3, 0))
defer function(2, function(4, 0))
}
- defer压栈function1,压栈函数地址、形参1、形参2(调用function3) —> 打印3
- defer压栈function2,压栈函数地址、形参1、形参2(调用function4) —> 打印4
- defer出栈function2, 调用function2 —> 打印2
- defer出栈function1, 调用function1—> 打印1
defer内变量的值是何时确定的? (补充1)
package main
import (
"fmt"
)
func function(value int) {
fmt.Println(value)
}
func main() {
x := 10
defer function(x)
x = 20
defer function(x)
}
defer内变量的值是何时确定的? (补充2)
package main
import (
"fmt"
)
func main() {
x := 10
defer func() {
fmt.Println(x)
}()
x = 20
defer func() {
fmt.Println(x)
}()
}