文档章节

从golang函数栈空间分布看defer,你就不会再错了

鼎铭
 鼎铭
发布于 06/18 17:29
字数 788
阅读 217
收藏 5
点赞 0
评论 0

    defer 是golang 面试常会面的一个点,但是实在话, 这玩意没多大用,特别是高频下,很多厂的优化点之一就是defer。但是这玩意复杂起来,你确实不一定能都答对,到底怎么分析defer ,才能保证返回值正常呢?其实明白 golang 的函数栈空间布局,就不会再弄错了。

    参考网上一哥们的文章,http://www.zenlife.tk/golang-defer.md,这个兄弟拿了三个例子,总结了一个方法,对于处理带复杂返回值的情况是有用的。

    首先做个测试题,如果全部都能做对,这篇文章就没必要看了,要是感觉有点瞎蒙,就还是看下:

ex1:

func f() (result int) {
    defer func() {
        result++
    }()
    return 0
}

ex2:

func f() (r int) {
     t := 5
     defer func() {
       t = t + 5
     }()
     return t
}

ex3:

func f() (r int) {
    defer func(r int) {
          r = r + 5
    }(r)
    return 1
}

    这三个例子基本涵盖了defer 最复杂的情况,而且非常有代表性。

   那个兄弟说的比较清楚了,他也总结了一个很好的方法,这里我不复述他说的内容,谈下自己的理解,他的方法是这样的,当出现defer 的时候,我们拆解成下面步骤:

返回值 = xxx
调用defer函数
空的return

    为什么这样是没问题的,有两个关键点,第一个,golang 的返回值是通过栈空间,不是通过寄存器,这点最重要。调用函数前,首先分配的是返回值空间,然后是入参地址,再是其他临时变量地址。第二点,return 是非原子的,return 操作的确是分三步,将返回值拷贝到栈空间第一块区域,然后再执行defer 操作,最后一个ret 跳转,这个操作的确是可以对应到汇编代码的。然后,这里第二步很巧妙,这里的返回值是否在定义的时候已经命名了?defer 是否能更改栈空间第一块区域的地址的值(是否在defer作用域)?这里画画图立马就能看明白。。。

    看ex1,函数栈空间如下图,这里没有入参,返回区域有名 result, result 在defer 的作用域,执行defer 的过程修改了result 的值,直接修改了函数返回值栈空间的值。所有,ex1的结果是1。

    再看ex2,函数的栈空间如下:

    

    注意下执行过程,这里的返回值地址r,根本不在defer 的作用域,defer 修改不了r的值,return t = 5 的时候,实际是 第一步:t = 5, 第二步,r = t, 第三步:defer 函数,第四部:ret 。从第四步的时候就不再修改r 的值了。

    最后看ex3就简单了,同样的方法,第一步 r = 1 ,返回值是有名的,这时,defer 入参是r 并不是r 地址,并不能修改r ,所以最后return 的值是1。

    上面的例子明白了,明白了函数的栈区分布基本defer 的返回值问题不会再错了。

 

© 著作权归作者所有

共有 人打赏支持
鼎铭
粉丝 22
博文 66
码字总数 39503
作品 0
东城
程序员
Go圣经-学习笔记之defer和异常处理

上一篇 Go圣经-学习笔记之函数值(二) 下一篇 Go圣经-学习笔记之方法 可变参数 形参数量可变的函数称为可变参数函数。使用最多的可变参数函数标准库:。 在声明可变参数函数时,需要在参数列表...

cdh0805010
2017/10/25
0
0
golang入门学习笔记(四)

作者: 一字马胡 转载标志 【2017-11-25】 更新日志 日期 更新内容 备注 2017-11-25 新建文章 go语言入门学习笔记(四) golang入门学习笔记系列 golang入门学习笔记(一) golang入门学习笔...

一字马胡
2017/11/25
0
0
golang捕获异常

Go语言追求简洁优雅,所以,Go语言不支持传统的 try…catch…finally 这种异常,因为Go语言的设计者们认为,将异常与控制结构混在一起会很容易使得代码变得混乱。因为开发者很容易滥用异常,...

吴之恒心
2017/03/01
0
0
Golang中多用途的defer

defer顾名思义就是延迟执行,那么defer在Golang中该如何使用以及何时使用呢? A "defer" statement invokes a function whose executionis deferred to the moment the surrounding function......

gotaly
06/26
0
0
Go的异常处理 defer, panic, recover

Go语言追求简洁优雅,所以,Go语言不支持传统的 try…catch…finally 这种异常,因为Go语言的设计者们认为,将异常与控制结构混在一起会很容易使得代码变得混乱。因为开发者很容易滥用异常,...

blacklovebear
2014/02/09
0
0
Golang defer 使用时的坑

defer是golang语言中的关键字,用于资源的释放,会在函数返回之前进行调用。一般采用如下模式: f,err := os.Open(filename)if err != nil { }defer f.Close() 如果有多个defer表达式,调用顺...

徐学良
2016/07/20
90
0
Golang 学习笔记(07)—— 错误及异常处理

本文为转载,原文:Golang 学习笔记(07)—— 错误及异常处理 Golang 基础知识 错误指的是可能出现问题的地方出现了问题,比如打开一个文件时失败,这种情况在人们的意料之中 ;而异常指的是...

ChainZhang
2017/12/28
0
0
【go语言】wait,wait for me

去年输出了一系列golang的编码文章,但总感觉有话没讲,但又不清楚具体是什么,所以本文以随笔为主。 我们知道函数的调用其实就是一个入栈和出栈的动作: main() --> normal() 如果用这个表示...

qingkechina
2017/02/05
0
0
golang学习的点点滴滴:异常处理 defer, panic, recover

Go语言追求简洁优雅,所以,Go语言不支持传统的 try…catch…finally 这种异常,因为Go语言的设计者们认为,将异常与控制结构混在一起会很容易使得代码变得混乱。因为开发者很容易滥用异常,...

亓斌哥哥
2014/09/29
0
0
golang各种场景下的协程调度饥饿问题

前言: 前段时间跟一个滴滴的小哥聊了关于golang饥饿调度的话题,似乎大家觉得golang不会出现太长时间饥饿。 但大家虽然看过golang sysmon抢占的源码实现,但不确定实际运行的结果是否跟预想的...

rfyiamcool
06/04
0
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

SpringBoot | 第十章:Swagger2的集成和使用

前言 前一章节介绍了mybatisPlus的集成和简单使用,本章节开始接着上一章节的用户表,进行Swagger2的集成。现在都奉行前后端分离开发和微服务大行其道,分微服务及前后端分离后,前后端开发的...

oKong
今天
2
0
Python 最小二乘法 拟合 二次曲线

Python 二次拟合 随机生成数据,并且加上噪声干扰 构造需要拟合的函数形式,使用最小二乘法进行拟合 输出拟合后的参数 将拟合后的函数与原始数据绘图后进行对比 import numpy as npimport...

阿豪boy
今天
1
0
云拿 无人便利店

附近(上海市-航南路)开了家无人便利店.特意进去体验了一下.下面把自己看到的跟大家分享下. 经得现场工作人员同意后拍了几张照片.从外面看是这样.店门口的指导里强调:不要一次扫码多个人进入....

周翔
昨天
1
0
Java设计模式学习之工厂模式

在Java(或者叫做面向对象语言)的世界中,工厂模式被广泛应用于项目中,也许你并没有听说过,不过也许你已经在使用了。 简单来说,工厂模式的出现源于增加程序序的可扩展性,降低耦合度。之...

路小磊
昨天
161
1
npm profile 新功能介绍

转载地址 npm profile 新功能介绍 npm新版本新推来一个功能,npm profile,这个可以更改自己简介信息的命令,以后可以不用去登录网站来修改自己的简介了 具体的这个功能的支持大概是在6这个版...

durban
昨天
1
0
Serial2Ethernet Bi-redirection

Serial Tool Serial Tool is a utility for developing serial communications, custom protocols or device testing. You can set up bytes to send accordingly to your protocol and save......

zungyiu
昨天
1
0
python里求解物理学上的双弹簧质能系统

物理的模型如下: 在这个系统里有两个物体,它们的质量分别是m1和m2,被两个弹簧连接在一起,伸缩系统为k1和k2,左端固定。假定没有外力时,两个弹簧的长度为L1和L2。 由于两物体有重力,那么...

wangxuwei
昨天
0
0
apolloxlua 介绍

##项目介绍 apolloxlua 目前支持javascript到lua的翻译。可以在openresty和luajit里使用。这个工具分为两种模式, 一种是web模式,可以通过网页使用。另外一种是tool模式, 通常作为大规模翻...

钟元OSS
昨天
2
0
Mybatis入门

简介: 定义:Mybatis是一个支持普通SQL查询、存储过程和高级映射的持久层框架。 途径:MyBatis通过XML文件或者注解的形式配置映射,实现数据库查询。 特性:动态SQL语句。 文件结构:Mybat...

霍淇滨
昨天
2
0
开发技术瓶颈期,如何突破

前言 读书、学习的那些事情,以前我也陆续叨叨了不少,但总觉得 “学习方法” 就是一个永远在路上的话题。个人的能力、经验积累与习惯方法不尽相同,而且一篇文章甚至一本书都很难将学习方法...

_小迷糊
昨天
1
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部