go 关键字之 defer
我是谁
defer - 顾名思义翻译过来叫 延迟, 所以我们通常称呼 defer func() 这样 defer 后面紧跟的函数为 延迟函数.
作者注: 不过从实际应用来讲, 延迟函数通常用来做一些函数最终返回前的一些收尾工作, 所以称呼为收尾函数其实更贴切.
三围几何
defer 有其独特的一面, 了解其个性, 才能更好的下手...对待妹纸, 应该也是这么个理
延迟性
顾名思义, 既然叫延迟函数, 那么肯定具备延迟性.
我们来看看怎么个延迟法, defer_defer.go
// defer_defer.go
package main
import (
"fmt"
)
func main() {
foo()
}
func foo() {
fmt.Println(1)
defer fmt.Println(2)
fmt.Println(3)
}
// go run defer_defer.go
// 1
// 3
// 2
可以看到 defer 定义的延迟函数最后才执行.
再来个例子, 如果一个函数内出现多个延迟函数, 延迟函数的执行顺序又是怎么样的呢?
// defer_filo.go
package main
import (
"fmt"
)
func main() {
foo()
}
func foo() {
defer fmt.Println(1)
defer fmt.Println(2)
defer fmt.Println(3)
}
// go run defer_filo.go
// 3
// 2
// 1
可以看到先定义的延迟函数后执行, 后定义的延迟函数先执行, 符合栈 (stack) 的先进后出 (FILO) 原则.
影响性
直接看代码, defer_impact.go
// defer_impact.go
package main
import (
"fmt"
)
func main() {
fmt.Println(foo())
}
func foo() (result int) {
defer func() {
result++
}()
return 0
}
// go run defer_defer.go
// 1
结果是不是跟想象有点不一样? 上述 foo() 可以改写为下:
func foo() (result int) {
result = 0
result++
return
}
go 中的 return 语句不是原子操作.
go 中 return 语句的操作过程为:
- 设置返回值
- 执行延迟函数
- 真正
return
所以延迟函数会影响主函数的返回值, 当然还要区分具名返回值/匿名返回值, 后话再说.
确定性
延迟函数的参数值, 在延迟函数首次出现时就确定了, 不受后续操作的影响.
我们来个例子: defer_parameters.go
// defer_parameters.go
package main
import (
"fmt"
)
func main() {
foo()
}
func foo() {
number := 1
defer fmt.Println(number)
number = 2
return
}
// go run defer_parameters.go
// 1
能做啥
- 打开数据链接, 要记得关闭, 可以用
defer - 操作完内存资源, 要记得释放, 可以用
defer - 想改变主函数的具名返回值, 可以用
defer- 通常不会这么干 - 想奇淫技巧, 可以用
defer- 偶尔 show 偶尔爽, 一直 show 一直爽 - 想搞事情, 可以用
defer- 请自行确保生命和财产安全 - ...
参考:
go 关键字之 defer的更多相关文章
- Go语言 关键字:defer
defer和go一样都是Go语言提供的关键字.defer用于资源的释放,会在函数返回之前进行调用.一般采用如下模式: f,err := os.Open(filename) if err != nil ...
- go语言defer关键字背后的实现,语法,用法
原文: https://tiancaiamao.gitbooks.io/go-internals/content/zh/03.4.html ------------------------------ ...
- go 学习笔记之咬文嚼字带你弄清楚 defer 延迟函数
温故知新不忘延迟基础 A "defer" statement invokes a function whose execution is deferred to the momen ...
- golang中defer的正确使用方式(源自深入解析go)
3.4 defer关键字 defer和go一样都是Go语言提供的关键字.defer用于资源的释放,会在函数返回之前进行调用.一般采用如下模式: f,err := os.Open(filename) i ...
- Javascript是单线程的深入分析
本来想总结一下的,网上却发现有人已经解释的很清楚了,特转过来. 这也解释了为什么在用自动化测试工具来运行dumrendtree时设定的超时和测试case设定的超时的关联性. 面试的时候发现99%的童鞋 ...
- 从C++到GO
从C++到GO 刚开始接触Go语言,看了两本Go语言的书,从c++开发者的角度来看看go语言的新特性,说下自己感触较深的几点: 并发编程 Go语言层面支持协程,将并发业务逻辑从异步转为同步,大幅提高开 ...
- 深入分析 Javascript 单线程
面试的时候发现99%的童鞋不理解为什么JavaScript是单线程的却能让AJAX异步发送和回调请求,还有setTimeout也看起来像是多线程的?还有non-blocking IO, event l ...
- go语法之一
Go语法: Go语言要求public的变量必须以 大写字母开头,private变量则以小写字母开头,这种做法不仅免除了public.private关键字,更重要的是统一了命名风格. Go语言对{ } ...
- 掌握一门语言Go
摘要:Go语言的优势不必多说,通过本篇文章,让我们花时间来掌握一门外语,Let's Go! 关键字:Go语言,闭包,基本语法,函数与方法,指针,slice,defer,channel,goroutin ...
随机推荐
- java中的浅拷贝和深拷贝
复制 将一个对象的引用复制给另一个对象,一共有三种方式.第一种方式是直接赋值,第二种方式是浅复制,第三种方式是深复制. 1.直接赋值 在Java中,A a1 = a2,这实际上复制的是引用,也就是说 ...
- Python3学习笔记(六):字符串
一.基本字符串操作 所有标准的序列操作(索引.分片.乘法.判断成员资格.求长度.取最小值和最大值)对字符串同样适用.但是字符串是不可改变的. 二.字符串格式化 字符串格式化使用字符串格式化操作符(%) ...
- springboot(六) Maven打包引入本地jar包
springboot Maven打包引入本地jar包 最近在做项目的时候,有一些jar包不存在maven的依赖库中,所以需要自己引入本地jar包来达到需求,那么我们该如何去将本地的jar包引入s ...
- java复制项目中的补丁,完整的包路径
package com.bytter.audit.iface.util; import java.io.BufferedInputStream; import java.io.BufferedOutp ...
- Window、Linux查看本机外网ip
前言 我们上网用的IP并不一定是本机网卡的IP地址,由于公网IP地址稀少,国内绝大多数电脑上网,一般都是通过拨号或者端口映射.多个内网地址映射到一个公网地址来实现上网的. 目录 1.查看本机网卡ip ...
- python 调用c++类方法(1)
myTest.cpp: #include<iostream> #include<vector> class MyTest { public: MyTest(); ~MyTest ...
- Hibernate一级缓存之懒加载问题
Hibernate的懒加载: 当用到数据的时候才向数据库查询,这就是hibernate的懒加载特性. 目的,为提高程序执行效率. 查询操作:get()方法/load()方法 (1)get()方法,及时 ...
- 思科端口聚合的命令是channel-group
锐捷设备的端口聚合命令是: int range f0/1-2 port-group 1 --------------------- == 思科设备的端口聚合 是: int range f0/1-2 c ...
- 浏览器端-W3School:JS & DOM 参考手册
ylbtech-浏览器端-W3School:JS & DOM 参考手册 1.返回顶部 1. JavaScript 参考手册 本部分提供完整的 JavaScript 参考手册: JavaScri ...
- Jmeter之内存溢出解决办法
使用Jmeter进行压力测试会遇到一段时间后报内存溢出的错误,导致Jmeter卡死.这是因为Jmeter默认的HEAP配置的太小了,解决办法如下: 1.Windows环境 修改jmeter.bat ...