Go学习--延迟调用机制:defer

Golang–谈谈defer

1、defer

defer是gol中的一种延迟调用机制,defer后面的函数只有当前函数执行完毕后才能执行

package main

import "fmt"

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

// 输出
1
3
2

2、多个defer执行顺序

多个defer出现的时候,会按照顺序压栈,然后先进后出的顺序执行。

package main

import "fmt"

func f1() {
	fmt.Println("1")
}

func f2() {
	fmt.Println("2")
}

func f3() {
	fmt.Println("3")
}

func main() {
	fmt.Println("0")
	defer f1()
	defer f2()
	defer f3()
	fmt.Println("4")
}
输出:
0
4
3
2
1

3、defer函数的参数传递

defer后面函数的参数在defer入栈时候就决定了,如果传的是引用,值才可能会改变。

  • 例1:值传递
package main

import "fmt"

func main() {
	x := 1
	defer func(i int){
		fmt.Println(i)  // 输出:1
	}(x) // 值传递,只是拷贝副本,保存的是入栈那一刻的值
	x++
}
  • 例2:引用传递
package main

import "fmt"

func main() {
	x := 1
	defer func(i *int){
		fmt.Println(i) // 输出:2
	}(&x) // 引用传递,传的是变量地址
	x++
}

4、defer与return顺序

首先看下return语句跟defer语句的区别:

image-20230921155129744

  • return顺序

    可以看出,return并不是原子性的,分为两个步骤。先返回值赋值,在RET指令。

  • defer顺序

    defer相当于插入在在return的两个步骤中间。

package main

import "fmt"

func deferFunc() {
	fmt.Println("defer func called")
}

func returnFunc() int {
	fmt.Println("return func called")
	return 0
}

func returnAndDefer() int {
	defer deferFunc()
	return returnFunc()
}

func main() {
	returnAndDefer()
}
输出:
return func called
defer func called

5、defer与panic

  • 当函数遇到panic,defer仍然会被执行。Go会先执行所有的defer链表(该函数的所有defer),当所有defer被执行完毕且没有recover时,才会进行panic。
  • defer 最大的功能是 panic 后依然有效,所以defer可以保证你的一些资源一定会被关闭,从而避免一些异常出现的问题。
  • 可以在defer中进行recover如果defer中包含recover,则程序将不会再进行panic,这就实现了Go中类似try-catch的机制。
package main

import "fmt"

func deferPanicFunc() {
	defer func() {
		fmt.Println("defer 处理资源关闭")
	}()
	panic("出错了")
}

func main() {
	deferPanicFunc()
}
输出:
defer 处理资源关闭
panic: 出错了

goroutine 1 [running]:
main.deferPanicFunc()
  • 可以在defer中recover
package main

import (
	"fmt"
)

func deferPanicFunc() {
	defer func() {
		// 捕获异常
		if err := recover(); err != nil {
			fmt.Println("捕获异常")
		} else {
			fmt.Println("defer 处理资源关闭")
		}
	}()
	// 抛出异常
	panic("出错了")
}

func main() {
	deferPanicFunc()
}
输出:
捕获异常

6、defer函数包含子函数

package main

import (
	"fmt"
)

func f(index int, value int) int {
	fmt.Println(index)
	return index
}

func main() {
	defer f(1, f(3, 0))
	defer f(2, f(4, 0))
}
分析:
先把f1压栈,为了得到第二个参数,要执行f3;
再把f2压栈,为了得到第二个参数,执行f4;
在执行f1,f2。
输出:
3
4
2
1

func f(index int, value int) int {
fmt.Println(index)
return index
}

func main() {
defer f(1, f(3, 0))
defer f(2, f(4, 0))
}


分析:
先把f1压栈,为了得到第二个参数,要执行f3;
再把f2压栈,为了得到第二个参数,执行f4;
在执行f1,f2。
输出:
3
4
2
1






评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值