概述
对于资源释放,有很多不同的实现方式,不同语言也有不同的惯用方法。
  • 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. vector的使用注意事项

    示例1: #include "iostream" #include "vector" using namespace std; int main(void) { ...

  2. Shared Virtual Memory (SVM) Functions

    Description Shared Virtual Memory (SVM) (Glossary): An address space exposed to both the host and th ...

  3. vue指令用法

    vue指令 指令式带有 v- 前缀的特殊特性v-text和v-html都属于指令将数据和dom做关联,当表达式的值改变时,响应式地作用在视图 解决大胡子语法闪烁案例 [v-cloak] { dispa ...

  4. ARC096 E Everything on It [容斥,斯特林数]

    Atcoder 一个900分的题耗了我这么久--而且官方题解还那么短--必须纪念一下-- 思路 发现每种元素必须出现两次以上的限制极为恶心,所以容斥,枚举出现0/1次的元素个数分别有几个.设出现1次的 ...

  5. Pytorch中ndarray tensor list互转

    1.ndarray->tensor : b=torch.from_numpy(a) 2.tensor->ndarray: b=a.numpy() ''' 但这么写会报错-- Runtime ...

  6. Oracle 03113

    SYSTEM的只有2M可以用了,还是需要 扩增 SYSTEM和SYSAUX的表空间 SELECT a.tablespace_name,a.bytes/1024/1024 total_M,b.bytes ...

  7. 原创:【ajax | axios跨域简单请求+复杂请求】自定义header头Token请求Laravel5后台【亲测可用】

    如标题:我想在ajax的header头增加自定义Token进行跨域api认证并调用,api使用laravel5编写,如何实现? 首先,了解下CORS简单请求和复杂请求.  -- CORS简单请求 -- ...

  8. Cookie的Secure属性和HttpOnly属性

    基于安全的考虑,需要给cookie加上Secure和HttpOnly属性,HttpOnly比较好理解,设置HttpOnly=true的cookie不能被js获取到,无法用document.cookie ...

  9. R3300L按reset键无法进入USB Burning模式的问题分析

    最开始并没有注意到这个问题, 因为从设备拿到手, 用USB Burning Tool刷入潜龙版的安卓4.4.2, 再到运行EmuELEC, Armbian, 再到给Kernel 5.3的Armbian ...

  10. jquery ajax Uncaught TypeError :Illegal invocation 报错

    使用jquery ajax异步提交的时候报Uncaught TypeError :Illegal invocation错误,报错如图: 基本上,导致这个错误的原因一般有以下两点: 1.请求类型有误,如 ...