在释放局部资源时, 可以用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. for循环的嵌套之小星星。

    for循环中如何打印出五行五列的小星星呢? 很明显行列的形式需要用到循环嵌套. 外循环控制行: var str = "" ; for(var  i= 1; i <= 5; i ...

  2. Python逆向(二)—— pyc文件结构分析

    一.前言 上一节我们知道了pyc文件是python在编译过程中出现的主要中间过程文件.pyc文件是二进制的,可以由python虚拟机直接执行的程序.分析pyc文件的文件结构对于实现python编译与反 ...

  3. Eureka 的高级使用

    基础架构Eureka架构中的三个核心角色: 服务注册中心 Eureka的服务端应用,提供服务注册和发现功能,就是刚刚我们建立的eureka-demo 服务提供者 提供服务的应用,可以是SpringBo ...

  4. c语言用指针定义一个类型进行输入输出

    1 整型数组 // #include "stdafx.h" #include "stdlib.h" int _tmain(int argc, _TCHAR* a ...

  5. An internal error occurred during: "Synchronizing"

    An internal error occurred during: "Synchronizing" “同步”期间发生内部错误. 处理方法 :单个文件进行更新,将无法更新的文件进行 ...

  6. Unknown column 'startname' in 'field list

    Unknown column 'startname' in 'field list  字段匹配不上 解决思路 1.检查数据库字段名与sql中的字段名是否一致 2.是否为关键字或中英文区别 ,(关键字可 ...

  7. Gamma阶段第三次scrum meeting

    每日任务内容 队员 昨日完成任务 明日要完成的任务 张圆宁 #91 用户体验与优化https://github.com/rRetr0Git/rateMyCourse/issues/91(持续完成) # ...

  8. abp 中log4net 集成Kafka

    1.安装包 Install-Package log4net.Kafka.Core 2.修改log4net.config 配置文件 <?xml version="1.0" en ...

  9. 【python基础学习】基础重点难点知识汇总

    python中decorator装饰器 语法示例: @decorator 什么是装饰器: 问题: 定义一个函数后 在运行时动态增加功能 又不想改动函数本身的代码 示例: # 希望对下列函数调用增加lo ...

  10. android细节之android.intent.category.DEFAULT的使用

    我们知道,实现android的Activity之间相互跳转需要用到Intent, Intent又分为显式Intent和隐式Intent, 显式Intent很简单,比如我在FirstActivity中想 ...