千恋*万花

  • 首页
  • 个人简历
  • 文章分类
    • 后端开发
    • 运维
    • 基础知识
    • 笔记
    • 工作运维记录
    • 随笔
    • 未分类文章
  • 管理
    • 后台管理
    • 登出
萌奈の笔记簿
分享我的努力,希望为你助力
  1. 首页
  2. 后端开发
  3. golang
  4. 正文

通过实践 总结 golang defer 的用法

2023-02-03 188点热度 1人点赞 0条评论

前言

用golang也用了挺长时间了,我对 defer 这个设计还比较满意,而且对其使用也产生了一些依赖,在使用其他编程语言写的入迷的时候,经常写出来 unknow type defer 的操作。

项目中,我用defer,一般是在 io 的时候使用,开启文件后,紧跟一个关闭,现在已经成为我的一种习惯了。

最近面试的时候,被问到了defer一些不常用的用法,虽然我都答出来了,但是答的过程有点曲折。我能把defer的大白话说出来,但是还是缺少总结语言的能力。

所以今天我想把 defer 用法的大白话,用代码让自己记住。

正文

defer 与 return 的先后顺序

先return,后执行defer,

defer 修改 return 的返回值

defer 可以修改有变量名的return值

  • “有变量名的return值”,指的是在声明函数时,所声明的返回值。

为什么是有变量值的return?
调用函数时,程序会为函数创建一块固定的区域,以存放 返回值,假设这块区域为 *p ,
函数return后,调用者会读取栈中的 *p 这一块内存区域。
使用 func f() (i int) 的方式声明函数,相当于为 *p 这片区域声明了一个变量名称 i,在defer中修改i的值,就相当于修改这片内存区域的值,所以 defer 可以修改函数的返回值。
若使用 func f() int 的方式声明函数,存放返回值的这片内存区域 *p 没有任何变量名称,最后的 return b 操作,只是将b的值复制给 *p 这片区域,return后,若在defer中修改b的值,也跟函数返回值 *p 没有任何关系了,所以 defer 无法修改没有声明变量名称的 返回值。

func f() (i int) {
    i = 100
    defer func() {
        i += 1
    }()
    return
}
func main() {
    fmt.Println(f())        // result 101
}

defer 链式调用

defer 遇到链式调用时,会先通过计算得到最后一个要执行的方法(函数),保留这个方法(函数)的指针、参数(值复制)。

type T struct{}

func (t T) f(n int) T {
    fmt.Println(n)
    return t
}

func main() {
    var t T
    defer t.f(1).f(2)
    fmt.Println(3)
}
// 打印结果
// 1    f(1)不是最后一个要执行的方法,所以先被defer计算了
// 3
// 2    f(2)被压入defer栈中,main()函数执行完毕以后才被执行

上述的 main() 函数,等同于:

    var t T
    tempT := t.f(1) //f(1)不是最后一个要执行的方法,所以先被defer计算了
    defer tempT.f(2)
    fmt.Print(3)

defer 参数值复制

defer 有参数的函数在压入 defer 栈时,会一并将此时参数的值,复制一份副本。defer函数执行时,函数实际的入参为当时保存的副本。

func f(n int) {
    defer fmt.Println(n)
    n += 100
}

func main() {
    f(1)
}
// 打印结果: 1

defer 匿名函数

匿名函数可以直接使用匿名函数外的变量,匿名函数中的 i ,与外部的 i 从内存地址的视角来看,是同一个 i。

func main() {
    i := 1
    defer func() {
        fmt.PrintLn(i)
    }()
    i += 100
}
// 打印结果:101
本作品采用 知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议 进行许可
标签: defer golang 实践心得
最后更新:2023-02-06

初音萌奈

我是练习时长 一年半 的后端开发程序员 谢谢你参观我的博客! 本网站现已支持IPv6 ☞ 个人简历 ☜

点赞
< 上一篇
下一篇 >

文章评论

取消回复
文章目录
  • 前言
  • 正文
    • defer 与 return 的先后顺序
    • defer 修改 return 的返回值
    • defer 链式调用
    • defer 参数值复制
    • defer 匿名函数

COPYRIGHT © 2023 HatsuneMona ALL RIGHTS RESERVED.

Theme Kratos Made By Seaton Jiang

晋ICP备17007130号-4