在释放局部资源时, 可以用defer管理

Go语言版本基于deferMutex用法

func safeRead(Mutex *mu) []byte {
mu.Lock()
defer mu.Unlock()
return read();
}

  

对于可能申请失败的资源也很好处理:

func loadFile(name string) ([]byte, error) {
f, err := os.Open(name)
if err != nil {
return nil, err
}
defer f.Close()
return load(f)
}

使用defer语句, 可以方便地组合函数/闭包和资源对象. 即使panic时, defer也能保证资源的正确释放.

defer

官方给出的文档上介绍defer的执行有三条基本规则:

1. defer函数是在外部函数return后,按照后申明先执行(栈)的顺序执行的;
package main

import "fmt"

func main() {
defer fmt.Println("1")
defer fmt.Println("2")
defer fmt.Println("3")
}

  

输出是

3
2
1
2. defer函数的参数的值,是在申明defer时确定下来的;

看几个例子吧,注意第一条规则。
这是一个普通类型的例子:

package main

import "fmt"

func main() {
i := 0 defer fmt.Println(i) // 这也算是作为defer函数的参数
defer func(j int) { fmt.Println(j) }(i) // 作为参数
defer func() { fmt.Println(i) }() // 作为闭包(closure)进行引用 i++
}

  

输出是:

1
0
0

如果是引用类型也是一样的道理:

  • 当修改引用对象的属性时:
  • package main
    
    import "fmt"
    
    type Person struct {
    name string
    } func main() {
    person := &Person{"Lilei"} defer fmt.Println(person.name) // person.name作为普通类型当做defer函数的参数
    defer fmt.Printf("%v\n", person) // 引用类型作为参数
    defer func(p *Person) { fmt.Println(p.name) }(person) // 同上
    defer func() { fmt.Println(person.name) }() // 闭包引用,对引用对象属性的修改不影响引用 person.name = "HanMeimei"
    }

      

    输出是:

    HanMeimei
    HanMeimei
    &{HanMeimei}
    Lilei
  • 当修改引用本身时:
package main

import "fmt"

type Person struct {
name string
} func main() {
person := &Person{"Lilei"} defer fmt.Println(person.name) // 同上,person.name作为普通类型当做defer函数的参数
defer fmt.Printf("%v\n", person) // 作为defer函数的参数,申明时指向“Lilei”
defer func(p *Person) { fmt.Println(p.name) }(person) // 同上
defer func() { fmt.Println(person.name) }() // 作为闭包引用,随着person的改变而指向“HanMeimei” person = &Person{"HanMeimei"}
}

  

输出是:

HanMeimei
Lilei
&{Lilei}
Lilei 在defer函数申明时,对外部变量的引用是有两种方式的,分别是作为函数参数和作为闭包引用。作为函数参数,则在defer申明时就把值传递给defer,并被cache起来。作为闭包引用的话,则会在defer函数执行时根据整个上下文确定当前的值。
3. defer函数可以读取和修改外部函数申明的返回值。

同样给一个例子

package main

import "fmt"

func main() {
fmt.Printf("output: %d\n", f())
} func f() (i int) {
defer fmt.Println(i) // 参数引用
defer func(j int) { fmt.Println(j) }(i) // 同上
defer func() { fmt.Println(i) }() // 闭包引用
defer func() { i++ }() // 执行前,i=2
defer func() { i++ }() // 执行前,i=1 i++ return
}

  

有了之前的基础,这个输出可以轻松推测出来:

3
0
0
output: 3

defer的基本规则就这三条了。了解之后,瞬间明朗了。

最开始的答案

通过defer的三条规则(其实只要前两条)就能知道输出了:

3
3
3
0
 
 

go 学习笔记 ----资源自动回收的更多相关文章

  1. 深入浅出PF 学习笔记---资源文件

    引用   xmlns:sys="clr-namespace:System;assembly=mscorlib" <Window.Resources><sys:St ...

  2. [原创]java WEB学习笔记69:Struts2 学习之路-- 消息处理与国际化,概述,配置国际资源文件,访问国际化消息,通过超链接切换语言

    本博客的目的:①总结自己的学习过程,相当于学习笔记 ②将自己的经验分享给大家,相互学习,互相交流,不可商用 内容难免出现问题,欢迎指正,交流,探讨,可以留言,也可以通过以下方式联系. 本人互联网技术爱 ...

  3. [原创]java WEB学习笔记55:Struts2学习之路---详解struts2 中 Action,如何访问web 资源,解耦方式(使用 ActionContext,实现 XxxAware 接口),耦合方式(通过ServletActionContext,通过实现 ServletRequestAware, ServletContextAware 等接口的方式)

    本博客的目的:①总结自己的学习过程,相当于学习笔记 ②将自己的经验分享给大家,相互学习,互相交流,不可商用 内容难免出现问题,欢迎指正,交流,探讨,可以留言,也可以通过以下方式联系. 本人互联网技术爱 ...

  4. (转) OpenCV学习笔记大集锦 与 图像视觉博客资源2之MIT斯坦福CMU

          首页 视界智尚 算法技术 每日技术 来打我呀 注册     OpenCV学习笔记大集锦 整理了我所了解的有关OpenCV的学习笔记.原理分析.使用例程等相关的博文.排序不分先后,随机整理的 ...

  5. Linux Shell编程学习笔记——目录(附笔记资源下载)

    LinuxShell编程学习笔记目录附笔记资源下载 目录(?)[-] 写在前面 第一部分 Shell基础编程 第二部分 Linux Shell高级编程技巧 资源下载 写在前面 最近花了些时间学习She ...

  6. Dynamic CRM 2015学习笔记(4)修改开发人员资源(发现服务、组织服务和组织数据服务)url地址及组织名

    在azure vm上安装了CRM 2015后 Dynamic CRM 2015学习笔记(1)Azure 上安装 CRM 2015, 发现了一个问题,那就是在设置 ->自定义项 –> 开发人 ...

  7. SpringBoot学习笔记(3):静态资源处理

    SpringBoot学习笔记(3):静态资源处理 在web开发中,静态资源的访问是必不可少的,如:Html.图片.js.css 等资源的访问. Spring Boot 对静态资源访问提供了很好的支持, ...

  8. 【转】Pro Android学习笔记(四):了解Android资源(下)

    处理任意的XML文件 自定义的xml文件放置在res/xml/下,可以通过R.xml.file_name来获取一个XMLResourceParser对象.下面是xml文件的例子: <rootna ...

  9. 【转】Pro Android学习笔记(三):了解Android资源(上)

    在Android开发中,资源包括文件或者值,它们和执行应用捆绑,无需在源代码中写死,因此我们可以改变或替换他们,而无需对应用重新编译. 了解资源构成 参考阅读Android学习笔记(三八):资源res ...

随机推荐

  1. Foxmail: 错误信息::ssl连接错误, errorCode: 5,各种解决方案的大杂烩。

    1.  收件数据过多,删除部分邮件可解决 我尝试失败,在foxmail把收件箱全部删完了没解决. 2.  网上最常见的解决方法 https://help.foxmail.com/cgi-bin/hel ...

  2. mybatis 根据多个id查询数据 foreach标签

    //根据设备多个id获取设备信息 public List<Devices> getDevicesAll(@Param("devicesIds") String[] de ...

  3. Java Array二维数组使用

    二维数组:元素为一维数组的数组 package myArray.arrayarray; /* *二维数组:元素为一维数组的数组 * * 定义格式: * A:数组类型[][] 数组名: (推荐用法) * ...

  4. layui上传文件组件(前后端代码实现)

    我个人博客系统上传特色图片功能就是用layui上传文件组件做的.另外采用某个生态框架,尽量都统一用该生态框架对应的解决方案,因为这样一来,有这么几个好处?1.统一而不杂糅,有利于制定相应的编码规范,方 ...

  5. Node.js之判断字符串中是否包含某个字符串

    server.txt内容如下: 阿里云服务器 关于应用场景,就不多说了,字符串是不论是后端开发还是前端开发等,都是要经常打交道了. test.js(node.js代码,只要被本地装了node.js环境 ...

  6. Linux文件系统被占用,磁盘使用量与实际不一致【转】

    用lsof检查后才发现原因是,有文件被删除,而进程还活着,因而造成还占用空间的现象 [root@/]# lsof |grep delete 根据lsof列出的进程号,kill这些进程后,空间就释放出来 ...

  7. Druid: A Real-time Analytical Data Store

    Druid一种实时数仓,针对的场景和目的,如下比较明确 Druid was originally designed to solve problems around ingesting and exp ...

  8. 分布式快照算法: Chandy-Lamport 算法

    转载https://zhuanlan.zhihu.com/p/53482103 这哥们写的好,顺便转过来吧,当做学习用. 分布式快照算法: Chandy-Lamport 算法 0. 引言 Spark ...

  9. python快速搭建http服务

    在Windows 7/10或Ubuntu上可以通过python2.x或python3.x来快速搭建一个简单的HTTP服务器. 如果python为2.x,则可执行:$ python -m SimpleH ...

  10. SVM – 回归

    SVM的算法是很versatile的,在回归领域SVM同样十分出色的.而且和SVC类似,SVR的原理也是基于支持向量(来绘制辅助线),只不过在分类领域,支持向量是最靠近超平面的点,在回归领域,支持向量 ...