golang之defer语句


defer语句会将其对应的函数延迟执行。

defer语句

defer语句用于延迟函数调用,每次会把一个函数压入栈中,函数返回前再把延迟的函数取出并执行。延迟函数可以有参数:

  • 延迟函数的参数在defer语句出现时就已确定下来(传值的就是当前值);
  • 延迟函数执行按后进先出顺序执行;
  • 延迟函数可操作主函数的具名返回值(修改返回值);

释放资源

defer 语句正好是在函数退出时执行的语句,所以使用 defer 能非常方便地处理资源释放、句柄关闭等问题。

func fileSize(filename string) int64 {
    f, err := os.Open(filename)
    if err != nil {
        return 0
    }
    // 延迟调用Close, 此时Close不会被调用
    defer f.Close()
	
    info, err := f.Stat()
    if err != nil {
        // defer机制触发, 调用Close关闭文件
        return 0
    }
    size := info.Size()
    // defer机制触发, 调用Close关闭文件
    return size
}

变量捕获

defer中的变量会被提前捕获,后续的修改不会影响到已捕获的值:

func deferTest() {
	i := 0
	defer fmt.Println("Defer:", i)
	i = 10
	fmt.Println("Fun:", i)
}

// Fun: 10
// Defer: 0  

defer语句中打印的值是修改前的值。

返回值影响

return不是原子操作, 执行过程是: 保存返回值(若有)—>执行defer( 若有) —>执行ret返回调用函数;

有具名返回值时,return可看做是以下语句的结合体:

返回值 = xxx
调用defer函数(依次逆序调用)
空的return

具名返回值

在defer中修改具名返回值时,会影响到函数的实际返回值。

func DeferShow() {
	fmt.Println("Out:", deferValueParam())
}
func deferValueParam() (ret int) {
	ret = 0

	defer func() { // 会直接修改栈中对应的返回值
		ret += 10
		fmt.Println("Defer Ret:", ret)
	}()
	ret = 5
	fmt.Println("Ret:", ret)
	return
}

// Ret: 5       
// Defer Ret: 15
// Out: 15  

非具名返回值

但是当函数为非具名返回值时,defer将无法影响返回值(因在return时,对应返回值已存入栈中):

func DeferShow() {
	fmt.Println("Out2:", deferValueParam())
}
func deferRetValue() int {
	ret := 0
	defer func() {
		ret += 10
		fmt.Println("Defer Ret:", ret)
	}()
	ret = 5
	return ret
}

// Defer Ret: 15
// Out2: 5  
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值