26 函数之内置函数

八 defer语句

8.1 defer介绍

Go语言中,函数内可以依次包含多个defer语句,在函数结束时,defer语句会逆序执行

func main() {
fmt.Println("start...")
defer fmt.Println(1)
defer fmt.Println(2)
defer fmt.Println(3)
fmt.Println("end...")
}

输出

start...
end...
3
2
1

由于defer语句延迟调用的特性,所以defer语句能非常方便的处理资源释放问题。比如:资源清理、文件关闭、解锁及记录时间等。

8.2 defer的执行时机

在Go语言的函数中return语句在底层并不是原子操作,它分为给返回值赋值和RET指令两步。而defer语句执行的时机就在返回值赋值操作后,RET指令执行前。具体如下图所示:

8.3 defer经典案例

下述代码运行结果是???

package main
import "fmt"
// 关键看,defer定义的函数内部是否引用的是func的返回值,如果是,则修改的就是返回值
func f1() int {
x := 5
defer func() {
x++ // 此处的x引用的是哪个位置的?x++是否影响返回值?
fmt.Println("f1===>",x) // 6
}()
return x
}
func f2() (y int) {
x := 5
defer func() {
x++ // 此处的x引用的是哪个位置的?x++是否影响返回值?
//y++
fmt.Println("f2===>",x) // 6
}()
return x
}
func f3() (x int) {
defer func(x int) {
x++ // 此处的x引用的是哪个位置的?x++是否影响返回值?
fmt.Println("f3===>",x) // 1
}(x)
return 5
}
func f4() (x int) {
defer func() {
x++ // 此处的x引用的是哪个位置的?x++是否影响返回值?
fmt.Println("f4===>",x) // 6
}()
return 5
}
func main() {
fmt.Println(f1())
fmt.Println(f2())
fmt.Println(f3())
fmt.Println(f4())
}

8.4 defer面试题

下述代码输出结果为???提示:在defer注册要延迟执行的函数时,该函数所有的参数的值都会被确定下来

func calc(index string, a, b int) int {
ret := a + b
fmt.Println(index, a, b, ret)
return ret
}
func main() {
x := 1
y := 2
defer calc("AA", x, calc("A", x, y))
x = 10
defer calc("BB", x, calc("B", x, y))
y = 20
}

九 内置函数

panic/recover

Go语言使用panic/recover模式来处理错误。 panic可以在任何地方引发,但recover只有在defer调用的函数中有效。 首先来看一个例子:

func funcA() {
fmt.Println("func A")
}
func funcB() {
panic("panic in B") // 主动抛出panic
}
func funcC() {
fmt.Println("func C")
}
func main() {
funcA()
funcB()
funcC()
}

输出:

func A
panic: panic in B
goroutine 1 [running]:
main.funcB(...)
.../code/func/main.go:12
main.main()
.../code/func/main.go:20 +0x98

程序运行期间funcB中引发了panic导致程序崩溃,异常退出了。这个时候我们就可以通过recover将程序恢复回来,继续往后执行。

func funcA() {
fmt.Println("func A")
}
func funcB() {
defer func() {
err := recover()
//如果程序出出现了panic错误,可以通过recover恢复过来
if err != nil {
fmt.Println("recover in B")
}
}()
panic("panic in B")
}
func funcC() {
fmt.Println("func C")
}
func main() {
funcA()
funcB()
funcC()
}

注意:

  1. recover()必须搭配defer使用。
  2. defer一定要在可能引发panic的语句之前定义。
上一篇
下一篇
Copyright © 2022 Egon的技术星球 egonlin.com 版权所有 沪ICP备2022009235号 沪公网安备31011802005110号 青浦区尚茂路798弄 联系方式-13697081366