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 效果相同
}

先来假设出结论,帮助大家理解

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

  2. 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、返回值之间执行顺序的更多相关文章

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

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

  2. 关于类中的参数类型和return返回值

    基础有些忘了,现在重新巩固一下 先定义一个Person类 class Person(): def __init__(self,name,age,height): self.name=name, sel ...

  3. C# 调用存储过程操作 OUTPUT参数和Return返回值

    本文转载:http://www.cnblogs.com/libingql/archive/2010/05/02/1726104.html 存储过程是存放在数据库服务器上的预先编译好的sql语句.使用存 ...

  4. MSSQL - 存储过程Return返回值

    1.存储过程中不使用外部参数. 存储过程: SET ANSI_NULLS ON GO SET QUOTED_IDENTIFIER ON GO -- ========================== ...

  5. 用jquery的ajax方法获取return返回值的正确姿势

    如果jquery中,想要获取ajax的return返回值,必须注意两方面,ajax的同步异步问题,在ajax方法里面还是外面进行return返回值. 下面列举了三种写法,如果想成功获取到返回值,参考第 ...

  6. 用jquery的ajax方法获取不到return返回值

    如果jquery中,获取不到ajax返回值. 两个错误写法会导致这种情况:1.ajax未用同步 2.在ajax方法中直接return返回值. 下面列举了三种写法,如果想成功获取到返回值,参考第三种写法 ...

  7. 关于ExecuteNonQuery执行存储过程的返回值 、、实例讲解存储过程的返回值与传出参数、、、C#获取存储过程的 Return返回值和Output输出参数值

    关于ExecuteNonQuery执行存储过程的返回值 用到过ExecuteNonQuery()函数的朋友们在开发的时候肯定这么用过. if(cmd.ExecuteNonQuery("xxx ...

  8. $.ajax() 获取不到return 返回值

    /*常见错误示例 直接在 ajax 里面return 结果 */ function demo(){ $.ajax({ url : 'test.do', type : "post", ...

  9. Python3入门系列之-----return返回值,我终于懂了

    前言 初学者学习return的用法有点蒙,不知道它的作用是什么?返回的是什么?在什么时候要用?小伙伴也可能会遇到和我同样的困扰,给大家举个例子,马上就明白了. 同一段代码,函数中带return和没有r ...

随机推荐

  1. HTML的属性

    data-的好处:对dom的一些自定义标识,通过这些标识符可以传递一些信息到相应的事件里:dom.dataset['属性名称'] 将节点变成数组 渐进式渲染:就是加载到哪里就显示到哪里 css和js的 ...

  2. plsql developer 使用sys用户登录,报ORA-01031权限不足,解决sys(dba权限用户)远程登录报错。

    数据库服务器架设在机器A上,此时我在机器B上进行远程连接,使用sys账号远程登录时报ORA-01031:insufficient privileges 或 ORA-01017: invalid use ...

  3. 《DSP using MATLAB》Problem 5.21

    证明: 代码: %% ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ...

  4. String的方法capitalize

    官方解释:Return a copy of the string with its first character capitalized and the rest lowercased.(返回字符串 ...

  5. JDBC封装

    在模拟servlet调用dao中,我们发现在dao的实现类中有许多重复代码,我们可以将其封装起来. 步骤: 一. 创建一个类 DBUtil 1加载驱动和建立链接的代码 完全一样 加载驱动写到静态代码快 ...

  6. .NET本质论 用类型编程

    运行时的类型 类型本身并不是万能的.类型真正有意思的地方在于,程序员使用类型的实例,并让它们相互作用.类型的实例(instance)既可以是对象,也可以是值,这取决于类型如何定义的.基本数据类型(pr ...

  7. mysql中 where in 用法详解

    这里分两种情况来介绍 1.in 后面是记录集,如: select  *  from  table  where   uname  in(select  uname  from  user); 2.in ...

  8. python之路---04 列表 元组

    十七 .列表 在python中使用[]来描述列表, 内部元素用逗号隔开. 对数据类型没有要求 1.列表存在索引和切片. 和字符串是一样的. 2.增删改查操作 1).增加 1. .append(&quo ...

  9. 关于TF-IDF的解释

    TF:term frequency ,词频 .指的是 term 出现的评率.词频和 2 个因数有关,在一个文档中出现这个词条次数越多,词频越高,文档总词条总数越多这个值被稀释. 所以  一般 TF = ...

  10. Eureka的高可用

    问题: 现在Eureka和Client是1对1,但是Eureka挂了,就不能用了. 如何解决呢,创建多个Erurka.并且Eureka进行相互注册.如下图 怎么相互注册呢 1. 创建两个Eureka ...