内容简介:本文源自defer语句在Go的函数中属于一个栈的形式,即在函数运行完成时,根据该语句出现的顺序 后进先出进行调用。从流程上来讲,类似于如下python代码:运行结果:
本文源自 https://blog.golang.org/defer-panic-and-recover
defer
defer语句在 Go 的函数中属于一个栈的形式,即在函数运行完成时,根据该语句出现的顺序 后进先出进行调用。从流程上来讲,类似于如下 python 代码:
def defer(func):
def wrapper(*args, **kwargs):
defers = []
kwargs['defers'] = defers
func(*args, **kwargs)
for f in reversed(defers):
f()
return wrapper
@defer
def foo(defers=None):
defers.append(lambda: print("1st defered function in foo"))
print("hello")
defers.append(lambda: print("2st defered function in foo"))
print("world")
defers.append(lambda: print("3st defered function in foo"))
if __name__ == "__main__":
foo()
运行结果:
root@arch tests: python defer.py hello world 3st defered function in foo 2st defered function in foo 1st defered function in foo
但是实际上Go中的defer和上面的代码有很大不同。Go的defer有三个特点:
- 被defer的函数的参数值在defer产生的那一行代码处就确定了
- defer的函数的执行顺序为后进先出----最后derfer的函数最先执行,它们都在函数 返回了值之后开始
- defer的函数可以修改函数返回值
我们来看一个例子:
package main
import "fmt"
func test_defer() {
var i int = 1
defer fmt.Println("1st in test_defer, i = ", i)
fmt.Println("hello")
i += 1
defer fmt.Println("1st in test_defer, i = ", i)
fmt.Println("world")
i += 1
defer fmt.Println("1st in test_defer, i = ", i)
}
func main() {
test_defer()
}
运行结果:
root@arch tests: go run defer.go hello world 1st in test_defer, i = 3 1st in test_defer, i = 2 1st in test_defer, i = 1
由此可证第一第二点。
接下来我们再看一个例子:
package main
import "fmt"
func test_defer() (i int){
defer func () {
fmt.Println(i)
i++
fmt.Println(i)
} ()
return 1
}
func main() {
i := test_defer()
fmt.Println(i)
}
运行结果:
root@arch tests: go run defer.go 1 2 2
由此可以看出,函数的执行过程是,执行函数体,然后到return语句,后进先出执行defer 语句,最后返回函数值。
panic, recover
他们俩都是内置函数,和Python中的raise和 try...except...
类似。值得注意的是,
即便函数在运行过程中发生了panic,也会执行完被defer的函数。
package main
import "fmt"
func caller() {
defer func () {
fmt.Println("defered anonymous function in caller")
} ()
callee()
if r := recover(); r != nil {
fmt.Println("recovered from callee")
}
}
func callee() {
panic(1111)
}
func main() {
caller()
}
运行结果:
root@arch tests: go run panic.go
defered anonymous function in caller
panic: 1111
goroutine 1 [running]:
panic(0x48a0a0, 0xc420056190)
/usr/lib/go/src/runtime/panic.go:500 +0x1a1
main.callee()
/root/tests/panic.go:19 +0x61
main.caller()
/root/tests/panic.go:10 +0x4e
main.main()
/root/tests/panic.go:24 +0x14
exit status 2
可以看出,在panic那一行,该函数立即退出,整个函数也立即退出,但是利用defer的 特性,我们可以做到异常处理:
package main
import "fmt"
func caller() {
defer func () {
fmt.Println("defered anonymous function in caller")
if r := recover(); r != nil {
fmt.Println("recovered from callee")
}
} ()
callee()
}
func callee() {
panic(1111)
}
func main() {
caller()
}
运行结果:
root@arch tests: go run panic.go defered anonymous function in caller recovered from callee
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:- 编译型语言、解释型语言、静态类型语言、动态类型语言概念与区别
- 计算机语言发展的三个阶段:机器语言、汇编语言与高级语言
- 凹 (“Wa”) 语言:可以嵌入 Go 语言环境的脚本语言
- Rust语言恰巧是一门解决了Go语言所有问题的语言
- 获取系统语言/当前 App支持语言
- 【Go 语言教程】Go 语言简介
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Vue.js前端开发
陈陆扬 / 人民邮电出版社 / 2017-2-1 / CNY 45.00
本书分为10章,包括简介、基础特性、指令、过滤器、过渡、组件、状态管理、常用插件、工程实例和Weex打包。本书从简单的单个实例和基础语法,到工程实例,将系统地讲述Vue.js在项目中的适用场景和具体操作。本书的特点在于案例详实,使读者体会到框架的优点和便捷之处,提升开发效率,最后能将Vue.js运用到实际项目中,避免纸上谈兵的尴尬。一起来看看 《Vue.js前端开发》 这本书的介绍吧!
图片转BASE64编码
在线图片转Base64编码工具
随机密码生成器
多种字符组合密码