defer
1.defer语句后面必须是函数调用,不能是语句,例如:
func hello() {
fmt.Println("hello")
}
func getString() string {
defer func(x int) {
fmt.Println(x)
}(1)
defer hello()
return "abd"
}
2.defer语句执行的函数在本函数执行完毕后执行
3.每次defer语句执行的时候,会把函数“压栈”,函数参数会被拷贝下来,在return前会按照出栈顺序执行这些函数,而执行这些函数的参数值可以是defer时的值,也可以是执行函数时的值,这主要看defer的是一个闭包还是一个函参传递,如果是函参传递,则值确定好了,如果是一个闭包则使用外部值,即最后确定的外部值。
4.defer函数执行的顺序:
1. 先给返回值赋值
2. 执行defer语句
3. 包裹函数return返回
举例:
func f1() int { //匿名返回值
var r int = 6
defer func() {
r *= 7
}()
return r
} //这里返回6,先复制r = 6然后执行defer语句
func f2() (r int) { //有名返回值
defer func() {
r *= 7
}()
return 6
}//这里返回42
func f3() (r int) { //有名返回值
defer func(r int) {
r *= 7
}(r)
return 6
}//这里返回6
f1的结果是6。f1是匿名返回值,匿名返回值是在return执行时被声明,因此defer声明时,还不能访问到匿名返回值,defer的修改不会影响到返回值。
f2先给返回值r赋值,r=6,执行defer语句,defer修改r, r = 42,然后函数return。
f3是有名返回值,但是因为r是作为defer的传参,在声明defer的时候,就进行参数拷贝传递,所以defer只会对defer函数的局部参数有影响,不会影响到调用函数的返回值。
panic
1.panic不仅可以传入string,也可以传入别的类型,例如
panic("panic!!!") //输出panic: panic!!!
panic([]int{1, 2}) //输出panic: ([]int) (0x49be80,0xc0000b6000)