在释放局部资源时, 可以用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. 修改git log中的Date格式

    默认的git log查看日志显示的格式如下: Date:   Thu Aug 16 17:44:32 2018 +0800 说实话,真不太喜欢这种日期格式还是换成数值比较舒服一点.git bash中使 ...

  2. ex1

    #include <stdio.h> int main() { int x; printf("输入一个整数: \n"); scanf("%d",&a ...

  3. Linux后台运行和关闭程序、查看后台任务

    fg.bg.jobs.&.ctrl+z   1.&    (最经常被用到)     这个用在一个命令的最后,可以把这个命令放到后台执行   2.ctrl + z     可以将一个正在 ...

  4. 第一章 Electron介绍 | Electron in Action(中译)

    Github 官方地址 代表作: Visual Studio Code Atom - Code editor. Github开源的代码编辑器,Electron起源地 Visual Studio Cod ...

  5. [算法模板]ST表

    [算法模板]ST表 ST表和线段树一样,都能解决RMQ问题(范围最值查询-Range Minimum Query). 我们开一个数组数组\(f[maxn][maxn\log_2]\)来储存数据. 定义 ...

  6. Net core学习系列(八)——Net Core日志

    一.简介# 日志组件,作为程序员使用频率最高的组件,给程序员开发调试程序提供了必要的信息.ASP.NET Core中内置了一个通用日志接口ILogger,并实现了多种内置的日志提供器,例如 Conso ...

  7. element UI中的select选择器的change方法需要传递多个值

    如果直接调用change事件,不传任何参数,则可以获取到当前选中的值(因为默认会将event参数传递过去) 场景: 你需要将select选择器 ”选中的当前元素“ 和 ”其他你需要的值“ 一起传递过去 ...

  8. vue-cli安装webpack项目及初始配置

    这个下载包是自己基于 webpack 搞的,可以看看https://github.com/chichengyu/webpack vue-cli安装 输入 npm install vue-cli -g ...

  9. TermKit的新一代Mac终端,在Ubuntu 11.04 轻松安装TermKit

    作为开发人员的必备工具,终端程序却一直没有什么大的变化,TermKit旨在改变这一切,作为下一代的命令行/终端程序,TermKit为我们提供了一个图形化的终端/命令行程序,它可以以可视化的方式展示终端 ...

  10. hive删除空分区

    当hive中分区字段有NULL值时,hive会使用dynamic partition,数据会放到一个特殊的分区,这个分区由参数“hive.exec.default.partition.name”控制, ...