defer基本用法和注意事项(go语言基础语法)

1.defer基本用法:

package main

import "fmt"

func sum(n1 int, n2 int) int {

	//当执行到defer时,暂时不执行,会将其压入一个独立的栈中
	//和sum栈和main栈不在一个地方的栈
	//当函数执行完毕后,再从defer栈中按照先入后出原则出栈
	defer fmt.Println("ok1,n1=", n1) //5.再执行这句
	defer fmt.Println("ok2,n2=", n2) //4.再执行这句
	res := n1 + n2                                //1.先执行了这句
	fmt.Println("ok3=", res, "n1=", n1, "n2", n2) //2.再执行这句
	return res                                    //3.再执行这句
}
func main() {
	res := sum(20, 30)
	fmt.Println("res=", res) //6.再执行这句
}

1.defer用于注册一个延迟调用
2.多个defer的执行顺序为“后进先出”;
3.所有函数在执行RET返回指令之前,都会先检查是否存在defer语句,若存在则先逆序调用defer语句进行收尾工作再退出返回;
4.匿名返回值是在return执行时被声明,有名返回值则是在函数声明的同时被声明,因此在defer语句中只能访问有名返回值,而不能直接访问匿名返回值;
5.return其实应该包含前后两个步骤:第一步是给返回值赋值(若为有名返回值则直接赋值,若为匿名返回值则先声明再赋值);第二步是调用RET返回指令并传入返回值, 而RET则会检查defer是否存在,若存在就先逆序插播defer语句,最后RET携带返回值退出函数;
6.因此,‍defer、return、返回值三者的执行顺序应该是:return最先给返回值赋值;接着defer开始执行一些收尾工作;最后RET指令携带返回值退出函数。

2.注意事项

再看下面一段代码:

package main

import "fmt"

func sum(n1 int, n2 int) int {

	defer fmt.Println("ok1,n1=", n1) 
	defer fmt.Println("ok2,n2=", n2)
	n1++
	n2++
	res := n1 + n2                                
	fmt.Println("ok3=", res, "n1=", n1, "n2", n2) 
	return res                                   
}

func main() {
	res := sum(20, 30)
	fmt.Println("res=", res) 
}

输出结果是:

ok3= 52 n1= 21 n2 31
ok2,n2= 30
ok1,n1= 20
res= 52

这段代码证明了:当defer把语句放入到入栈时,如果涉及到值时,会将相应的值拷贝同时入栈

再看下面这段代码:

package main

import "fmt"

func sum(n1 *int, n2 *int) int {
	defer fmt.Println("ok1,n1=", *n1) 
	defer fmt.Println("ok2,n2=", *n2)                 
	*n1++
	*n2++
	res := *n1 + *n2 
	fmt.Println("ok3=", res, "n1=", *n1, "n2", *n2) 
	return res                                      
}

func main() {
	n1 := 20
	n2 := 30
	var p1 *int = &n1
	var p2 *int = &n2
	res := sum(p1, p2)
	fmt.Println("res=", res)
}

输出结果是:

ok3= 52 n1= 21 n2 31
ok2,n2= 30
ok1,n1= 20
res= 52

实践证明引用传递入栈时也是拷贝入栈

3.defer最主要的作用

当函数执行完毕后,及时释放函数所创建的资源
例如下面的例子:
1.

func test(){
//关闭文件资源
file=openfile(文件名)
defer  file.close()
//写在打开文件语句后是因为:
//怕自己最后忘了关闭文件,因此在打开的时候便写defer 关闭
//同时后续还可以使用这个文件
//传统php,java资源关闭不易控制时机
//使得我们不再为什么时候关闭资源感到烦恼
}
func test(){
//释放数据库资源
connect=openDatebse()
defer connect.close()
//其余代码
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

是一只土拨鼠呐

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值