概述
对于资源释放,有很多不同的实现方式,不同语言也有不同的惯用方法。
  • C语言 :手动管理
  • Golang :defer
  • Python :上下文管理器contexManager
  • C++ : 作用域和析构函数
  • Rust :所有权和drop trait
如果了解上面几种语言的童鞋应该知道,
C语言资源管理是比较麻烦的,一旦资源使用过程中出错,就可能造成资源泄漏。
Golang通过defer,即使过程中panic,也可以释放资源。
Python通过上下文管理器,主要是两个magic function`__enter__`, `__exit__`来保证资源的释放。
C++和Rust相似,都是在某种语义下自动调用释放函数。但是Rust有所有权检查,可以防止写代码犯傻 (比如C++不小心拷贝了一下。)
 
 
以上来看,C++和Rust的必须要在编程时注意释放的时机,也就是需要程序员更多的思考。但是Rust编译器会帮你一下,而C++并不会。
其次Python和Golang都使用了显式管理,一定不能忘了做,不过做了问题就不大了。
 
defer
不过这是一篇关于derfer的文章,写一下defer需要注意的重点(就是读Effective Go的一点笔记)。
 
基本使用
`defer语句将函数调用安排在当前函数结束前执行。也就是defer 语句中的函数调用是当前函数最后执行的东西`
- 一个经典的例子
 // Contents returns the file's contents as a string.
 func Contents(filename string) (string, error) {
     f, err := os.Open(filename)
     if err != nil {
         return "", err
     }
     defer f.Close()  // f.Close will run when we're finished.

     var result []byte
     buf := make([])
     for {
         n, err := f.Read(buf[:])
         result = append(result, buf[:n]...) // append is discussed later.
         if err != nil {
             if err == io.EOF {
                 break
             }
             return "", err  // f will be closed if we return here.
         }
     }
     return string(result), nil // f will be closed if we return here.
 }
 
用上面的话翻译代码中的`defer f.Close()`就是“将f.Close()放在Contents函数的最后执行”
将`f.Close()`放在defer后面有两个好处:保证资源释放、离`Open`比较近不会忘了做。
这没什么好说的,golang必须显式释放资源。
 
细节
首先明确两个概念
- defer语句执行
    将defer语句中函数调用安排在了当前函数结束前执行
- 函数调用执行
    运行defer语句中的函数调用
 
参数求值
这里的参数求值指的是defer语句中函数调用的参数。
参数在defer语句执行求值,而不是在函数调用执行时求值。
- 又一个例子
func trace(s string) string {
    fmt.Println("entering:", s)
    return s
}

func un(s string) {
    fmt.Println("leaving:", s)
}

func a() {
    defer un(trace("a"))
    fmt.Println("in a")
}

func b() {
    defer un(trace("b"))
    fmt.Println("in b")
    a()
}

func main() {
    b()
}
首先看函数b,因为参数是在defer语句执行时求值的,所以`trace("b")`要先被求值[先打印"b",再返回"b"],然后再往下执行,在函数b结束之前会调用`un("b")`.
同理如函数a。现在猜一下执行结果。
 
entering: b
in b
entering: a
in a
leaving: a
leaving: b
 
执行顺序
当有多个defer语句的时候,到底是谁的函数调用先执行呢?
 
 ; i < ; i++ {
     defer fmt.Printf("%d ", i)
 }

defer的函数调用按着后进先出(LIFO)的方式执行。大概猜一猜,每次defer都会将函数调用压入栈中,最后依次出栈执行。

 
最后
golang中defer也就主要用在资源管理上了。明确以上几点问题,应该问题不大了(吹牛ing)。
 
 

golang之defer的更多相关文章

  1. 关于golang的defer的练习

    golang的defer怎么说.大意就是在函数return后.函数关闭前.按照filo的顺序来执行的关键字 上代码: package main import ( "fmt" ) f ...

  2. golang学习 ---defer语句

    golang语言defer特性详解 defer语句是go语言提供的一种用于注册延迟调用的机制,它可以让函数在当前函数执行完毕后执行,是go语言中一种很有用的特性.由于它使用起来简单又方便,所以深得go ...

  3. 延宕执行,妙用无穷,Go lang1.18入门精炼教程,由白丁入鸿儒,Golang中defer关键字延迟调用机制使用EP17

    先行定义,延后执行.不得不佩服Go lang设计者天才的设计,事实上,defer关键字就相当于Python中的try{ ...}except{ ...}finally{...}结构设计中的finall ...

  4. golang中defer的使用规则

    转自个人博客chinazt.cc 在golang当中,defer代码块会在函数调用链表中增加一个函数调用.这个函数调用不是普通的函数调用,而是会在函数正常返回,也就是return之后添加一个函数调用. ...

  5. [转]golang中defer的使用规则

    转载于:https://studygolang.com/articles/10167 在golang当中,defer代码块会在函数调用链表中增加一个函数调用.这个函数调用不是普通的函数调用,而是会在函 ...

  6. golang中defer的理解

    在golang当中,defer代码块会在函数调用链表中增加一个函数调用.这个函数调用不是普通的函数调用,而是会在函数正常返回,也就是return之后添加一个函数调用.因此,defer通常用来释放函数内 ...

  7. 【GoLang】golang 中 defer 参数的蹊跷

    参考资料: http://studygolang.com/articles/7994--Defer函数调用参数的求值 golang的闭包和普通函数调用区别:http://studygolang.com ...

  8. golang 之 defer(统计函数执行时间)

    package main import ( "fmt" "time" ) func sum(a ...int) int { defer trace(" ...

  9. golang中defer的详解 转自https://blog.csdn.net/skh2015java/article/details/77081250

    Go里的defer很有用,尤其在很多执行模块化操作时,初始化时给各个需要执行的模块传入参数,但是这些参数有些事在模块执行过程中才赋值的. 这时候有了defer就不会把代码写的很凌乱. Go的defer ...

随机推荐

  1. webstorm永久破解

    准备 1. webstorm下载 本次使用的是2017.3.3版本,如果找不到那么在此附上:webstorm各版本下载地址. 前段时间有朋友反馈破解不成功,今天本人亲测2017.3.3仍可以破解成功, ...

  2. 【牛客】路径计数机 (树形dp 前缀和)

    题目描述 有一棵n个点的树和两个整数p, q,求满足以下条件的四元组(a, b, c, d)的个数:  1.$1\leq a,b,c,d \leq n$  2.点a到点b的经过的边数为p.  3.点c ...

  3. 第01组 团队Git现场编程实战

    目录 一.组员职责分工 二.github 的提交日志截图(鼓励小粒度提交) 三.程序运行截图 四.程序运行环境 五.GUI界面 六.基础功能实现 七.鼓励有想法且有用的功能 八.遇到的困难及解决方法 ...

  4. 记一次netty http server给客户端返回reset包排除

    类似文章:解决用netty去做web服务时,post长度过大的问题 现象:当客户端给server发送的请求体较大时,服务直接给客户端返回reset包. tcpdump: 应用还没有完全收上去,就clo ...

  5. php – 通过curl从url获取JSON数据

    我试图通过curl连接从URL获取JSON数据.当我打开链接时:它显示{“version”:“N / A”,“success”:true,“status”:true}.现在,我希望获得以上内容. 到目 ...

  6. 阿里云ecs centos yarn 安装

    安装流程:https://yarn.bootcss.com/docs/install/#centos-stable

  7. 面试突击(八)——JVM的结构及内存模型,是怎么划分的?

    声明:本文图片均来自网络,我只是进行了选择,利用一图胜千言的力量来帮助自己快速的回忆相关的知识点 0:再上一张Java代码的转换流程图 .java——Java程序员编写,给人看的 .class——Ja ...

  8. 【转载】 TensorFlow函数:tf.Session()和tf.Session().as_default()的区别

    原文地址: https://blog.csdn.net/Enchanted_ZhouH/article/details/77571939 ------------------------------- ...

  9. 连接池-Mybatis源码

    持续更新:https://github.com/dchack/Mybatis-source-code-learn Mybatis连接池 有这么个定律,有连接的地方就有池. 在市面上,可以适配Mybat ...

  10. 报错:pymysql.err.InternalError: (1054, "Unknown column 'AType' in 'field list'")

    报错背景: 报错前sql代码展示: List = ['] # sql = "insert into test(id, name) value ("+"'"+ L ...