Go 中 defer 和 return 执行的先后顺序

  1. 多个defer的执行顺序为“后进先出”;

  2. defer、return、返回值三者的执行逻辑应该是:return最先执行,return负责将结果写入返回值中;接着defer开始执行一些收尾工作;最后函数携带当前返回值退出。

如果函数的返回值是无名的(不带命名返回值),则go语言会在执行return的时候会执行一个类似创建一个临时变量作为保存return值的动作,而有名返回值的函数,由于返回值在函数定义的时候已经将该变量进行定义,在执行return的时候会先执行返回值保存操作,而后续的defer函数会改变这个返回值(虽然defer是在return之后执行的,但是由于使用的函数定义的变量,所以执行defer操作后对该变量的修改会影响到return的值

eg1:不带命名返回值的函数

package main

import "fmt"

func main() {
fmt.Println("return:", test())// defer 和 return之间的顺序是先返回值, i=0,后defer
} func test() int {//这里返回值没有命名
var i int
defer func() {
i++
fmt.Println("defer1", i) //作为闭包引用的话,则会在defer函数执行时根据整个上下文确定当前的值。i=2
}()
defer func() {
i++
fmt.Println("defer2", i) //作为闭包引用的话,则会在defer函数执行时根据整个上下文确定当前的值。i=1
}()
return i
} 

test() 先返回 i=0

defer2先于defer1执行

输出结果为:

defer2 1

defer1 2

return: 0

eg2:带命名返回值的函数:

package main

import "fmt"

func main() {
fmt.Println("return:", test())
} func test() (i int) { //返回值命名i
defer func() {
i++
fmt.Println("defer1", i)
}()
defer func() {
i++
fmt.Println("defer2", i)
}()
return i
}
对外部变量的引用作为函数参数(i),则在defer申明时就把值传递给defer,

 

 输出结果为:

defer2 1

defer1 2

return: 2

理解return 返回值的运行机制:

为了弄清上述两种情况的区别,我们首先要理解return 返回值的运行机制:
return 并非原子操作,分为赋值,和返回值两步操作
eg1 : 实际上return 执行了两步操作,因为返回值没有命名,所以
return 默认指定了一个返回值(假设为s),首先将i赋值给s,后续
的操作因为是针对i,进行的,所以不会影响s, 此后因为s不会更新,所以
return s 不会改变
相当于:
var i int
s := i
return s
eg2 : 同上,s 就相当于 命名的变量i, 因为所有的操作都是基于
命名变量i(s),返回值也是i, 所以每一次defer操作,都会更新
返回值i

 

Go ---- defer 和 return 执行的先后顺序的更多相关文章

  1. go中defer的理解--defer、return、返回值之间执行顺序

    defer可以读取有名返回值 func c() (i int) { defer func() { i++ }() return 1 } 输出结果是2. 在开头的时候,我们知道defer是在return ...

  2. Golang中defer、return、返回值之间执行顺序的坑

    原文链接:https://studygolang.com/articles/4809 Go语言中延迟函数defer充当着 cry...catch 的重任,使用起来也非常简便,然而在实际应用中,很多go ...

  3. go defer、return的执行顺序

    一.一个函数中多个defer的执行顺序 defer 的作用就是把defer关键字之后的函数执行压入一个栈中延迟执行,多个defer的执行顺序是后进先出LIFO,也就是先执行最后一个defer,最后执行 ...

  4. defer、return、返回值,这三者的执行逻辑

    defer.return.返回值,这三者的执行逻辑是: return 最先执行,return 负责将结果写入返回值中:接着defer执行,可能修改返回值:最后函数携带当前返回值退出.

  5. finally return 执行顺序问题

    网上有很多人探讨Java中异常捕获机制try...catch...finally块中的finally语句是不是一定会被执行?很多人都说不是,当然他们的回答是正确的,经过我试验,至少有两种情况下fina ...

  6. Swift - defer关键字(推迟执行)

    在一些语言中,有try/finally这样的控制语句,比如Java. 这种语句可以让我们在finally代码块中执行必须要执行的代码,不管之前怎样的兴风作浪. 在Swift 2.0中,Apple提供了 ...

  7. 异常 try catch finally return 执行关系 MD

    Markdown版本笔记 我的GitHub首页 我的博客 我的微信 我的邮箱 MyAndroidBlogs baiqiantao baiqiantao bqt20094 baiqiantao@sina ...

  8. Vue中父子组件执行的先后顺序

    Vera   Vue中父子组件执行的先后顺序探讨(转载) 前几天,朋友向我提出了一个关于Vue中父子组件执行的先后顺序问题,相信很多朋友在学习的过程中也会遇到这个问题,所以我就在此提出我自己的一些小看 ...

  9. Vue中父子组件执行的先后顺序探讨

    前几天,朋友向我提出了一个关于Vue中父子组件执行的先后顺序问题,相信很多朋友在学习的过程中也会遇到这个问题,所以我就在此提出我自己的一些小看法. 问题如下:请问下图中父子组件执行的先后顺序? 首先, ...

随机推荐

  1. nginx 常用全局变量

    变量 说明 $args 请求中的参数,如www.123.com/1.php?a=1&b=2的$args就是a=1&b=2 $content_length HTTP请求信息里的" ...

  2. Ubuntu 14.04 安装python3.7

    下载: https://www.python.org/ftp/python/3.7.4/ .tgz文件,解压后,进入该文件夹 编译./configuremakesudo make install 当 ...

  3. 条件随机场CRF原理介绍 以及Keras实现

    本文是对CRF基本原理的一个简明的介绍.当然,“简明”是相对而言中,要想真的弄清楚CRF,免不了要提及一些公式,如果只关心调用的读者,可以直接移到文末. 图示# 按照之前的思路,我们依旧来对比一下普通 ...

  4. linux 如何改变文件属性与权限1

    我们知道档案权限对于一个系统的安全重要性,也知道档案的权限对于使用者与群组的相关性, 那如何修改一个档案的属性与权限呢? 我们这里介绍几个常用于群组.拥有者.各种身份的权限的指令.如下所示: chgr ...

  5. Spring中为什么继承了ApplicationContextAware接口就可以使用ApplicationContext对象?

    1.Spring中使用applicationContext对象 public class SpringContextUtil implements ApplicationContextAware { ...

  6. C++ 已知两个时间(年月日)求日期差

    转载:https://blog.csdn.net/flyyufenfei/article/details/79796035 #include<iostream> #include < ...

  7. 行车记录仪 MyCar Recorder (转)

    行车记录仪 MyCar Recorder

  8. CentOS7下的CDH 6.2.0 安装过程

    #install OS centos 7.5#install lsb packageyum install -y redhat-lsb #install net-tools package yum i ...

  9. mark_Linux_wc

    Linux wc命令 Linux wc命令用于计算字数. 利用wc指令我们可以计算文件的Byte数.字数.或是列数,若不指定文件名称.或是所给予的文件名为"-",则wc指令会从标准 ...

  10. 文档工具的王者Sphinx

    Sphinx https://www.sphinx.org.cn/ Sphinx是一个工具,可以轻松创建由Georg Brandl编写并根据BSD许可证授权的智能和美观文档 它最初是为Python文档 ...