go中defer的理解--defer、return、返回值之间执行顺序
defer可以读取有名返回值
func c() (i int) {
defer func() { i++ }()
return 1
}
输出结果是2. 在开头的时候,我们知道defer是在return调用之后才执行的。 这里需要明确的是defer代码块的作用域仍然在函数之内,结合上面的函数也就是说,defer的作用域仍然在c函数之内。因此defer仍然可以读取c函数内的变量(如果无法读取函数内变量,那又如何进行变量清除呢....)。
当执行return 1 之后,i的值就是1. 此时此刻,defer代码块开始执行,对i进行自增操作。 因此输出2.
A. 无名返回值的情况
package main import (
"fmt"
) func main() {
fmt.Println("return:", a()) // 打印结果为 return: 0
} func a() int {
var i int
defer func() {
i++
fmt.Println("defer2:", i) // 打印结果为 defer: 2
}()
defer func() {
i++
fmt.Println("defer1:", i) // 打印结果为 defer: 1
}()
return i
}
B. 有名返回值的情况
package main import (
"fmt"
) func main() {
fmt.Println("return:", b()) // 打印结果为 return: 2
} func b() (i int) {
defer func() {
i++
fmt.Println("defer2:", i) // 打印结果为 defer: 2
}()
defer func() {
i++
fmt.Println("defer1:", i) // 打印结果为 defer: 1
}()
return i // 或者直接 return 效果相同
}
先来假设出结论,帮助大家理解
多个defer的执行顺序为“后进先出”;
defer、return、返回值三者的执行逻辑应该是:return最先执行,return负责将结果写入返回值中;接着defer开始执行一些收尾工作;最后函数携带当前返回值退出。
如何解释两种结果的不同:
上面两段代码的返回结果之所以不同,其实从上面第2条结论很好理解。
a()int 函数的返回值没有被提前声明,其值来自于其他变量的赋值,而defer中修改的也是其他变量,而非返回值本身,因此函数退出时返回值并没有被改变。
b()(i int) 函数的返回值被提前声明,也就意味着defer中是可以调用到真实返回值的,因此defer在return赋值返回值 i 之后,再一次地修改了 i 的值,最终函数退出后的返回值才会是defer修改过的值。
C. 下面我们再来看第三个例子,验证上面的结论:
package main import (
"fmt"
) func main() {
fmt.Println("c return:", *(c())) // 打印结果为 c return: 2
} func c() *int {
var i int
defer func() {
i++
fmt.Println("c defer2:", i) // 打印结果为 c defer: 2
}()
defer func() {
i++
fmt.Println("c defer1:", i) // 打印结果为 c defer: 1
}()
return &i
}
虽然 c()*int 的返回值没有被提前声明,但是由于 c()*int 的返回值是指针变量,那么在return将变量 i 的地址赋给返回值后,defer再次修改了 i 在内存中的实际值,因此函数退出时返回值虽然依旧是原来的指针地址,但是其指向的内存实际值已经被成功修改了。
即,我们假设的结论是正确的!
go中defer的理解--defer、return、返回值之间执行顺序的更多相关文章
- Golang中defer、return、返回值之间执行顺序的坑
原文链接:https://studygolang.com/articles/4809 Go语言中延迟函数defer充当着 cry...catch 的重任,使用起来也非常简便,然而在实际应用中,很多go ...
- 关于类中的参数类型和return返回值
基础有些忘了,现在重新巩固一下 先定义一个Person类 class Person(): def __init__(self,name,age,height): self.name=name, sel ...
- C# 调用存储过程操作 OUTPUT参数和Return返回值
本文转载:http://www.cnblogs.com/libingql/archive/2010/05/02/1726104.html 存储过程是存放在数据库服务器上的预先编译好的sql语句.使用存 ...
- MSSQL - 存储过程Return返回值
1.存储过程中不使用外部参数. 存储过程: SET ANSI_NULLS ON GO SET QUOTED_IDENTIFIER ON GO -- ========================== ...
- 用jquery的ajax方法获取return返回值的正确姿势
如果jquery中,想要获取ajax的return返回值,必须注意两方面,ajax的同步异步问题,在ajax方法里面还是外面进行return返回值. 下面列举了三种写法,如果想成功获取到返回值,参考第 ...
- 用jquery的ajax方法获取不到return返回值
如果jquery中,获取不到ajax返回值. 两个错误写法会导致这种情况:1.ajax未用同步 2.在ajax方法中直接return返回值. 下面列举了三种写法,如果想成功获取到返回值,参考第三种写法 ...
- 关于ExecuteNonQuery执行存储过程的返回值 、、实例讲解存储过程的返回值与传出参数、、、C#获取存储过程的 Return返回值和Output输出参数值
关于ExecuteNonQuery执行存储过程的返回值 用到过ExecuteNonQuery()函数的朋友们在开发的时候肯定这么用过. if(cmd.ExecuteNonQuery("xxx ...
- $.ajax() 获取不到return 返回值
/*常见错误示例 直接在 ajax 里面return 结果 */ function demo(){ $.ajax({ url : 'test.do', type : "post", ...
- Python3入门系列之-----return返回值,我终于懂了
前言 初学者学习return的用法有点蒙,不知道它的作用是什么?返回的是什么?在什么时候要用?小伙伴也可能会遇到和我同样的困扰,给大家举个例子,马上就明白了. 同一段代码,函数中带return和没有r ...
随机推荐
- linux面试题(自己添加了一些注释说明)
1.linux如何挂在windows下的共享目录 首先需要在Windows中创建一个文件夹用来共享,例如下面就是server是用来共享的,貌似在哪个位置创建都可以,我是在d盘创建的 1 mount.c ...
- Rendering on the Web
转自: https://developers.google.com/web/updates/2019/02/rendering-on-the-web Rendering on the Web Goog ...
- Unity3d插件开发与SDK对接实战 学习
c++: 注意x86/x64,vs2015. #include "stdafx.h" extern "C" { int Add(int a, int b) { ...
- Spring技术内幕总结 - AOP概述
AOP是Aspect-Oriented Programming(面向方面/切面编程)的简称.Aspect是一种新的模块化机制,用来描述分散在对象.类或函数中的横切关注点.分离关注点使解决特定领域问题的 ...
- MySQL 5.7新特性之在线收缩undo表空间
1. MySQL 5.5时代的undo log 在MySQL5.5以及之前,大家会发现随着数据库上线时间越来越长,ibdata1文件(即InnoDB的共享表空间,或者系统表空间)会越来越大,这会造成2 ...
- git add -A /git add -u/git add .的用法
git的指令详解 在git中有好多的指令,但是今天这几个指令就很容易忘记而且还容易混淆 git add -u <==> git add –update 提交所有被删除和修改的文件到数据暂存 ...
- Linux 如何配置虚拟机下的Centos静态ip
如何配置虚拟机下的Centos静态ip 1. 配置虚拟机的虚拟路由器 2. 配置物理主机的虚拟网卡(VMNET8) 3. 配置虚拟主机Centos的网卡 vi ...
- shonc-聊天im工具配置
linux系统配置部分 1. 安装nodejs 切换到/usr/local/src/目录下 wget http://nodejs.org/dist/v0.10.25/node-v0.10.25-lin ...
- 看图写代码---看图写代码 阅读<<Audio/Video Connectivity Solutions for Virtex-II Pro and Virtex-4 FPGAs >>
看图写代码 阅读<<Audio/Video Connectivity Solutions for Virtex-II Pro and Virtex-4 FPGAs >> 1.S ...
- django 数据模型中 null=True 和 blank=True 有什么区别
null: If True, Django will store empty values as NULL in the database. Default is False. 如果为True,空值将 ...