以前讲过golang 的基本语法。但是,只是讲了一些基础的语法,感兴趣的可以看看以前的文章,https://www.cnblogs.com/zhangweizhong/category/1275863.html,前段时间有人问我defer,recover的用法。所以,还是统一的总结一下相关的关键字吧。

其实,Go语言是不支持 try…catch…finally 这种异常处理的,因为Go语言的设计者们认为,将异常与控制结构混在一起会很容易使得代码变得混乱。因为开发者很容易滥用异常,甚至一个小小的错误都抛出一个异常。
在Go语言中,使用多值返回来返回错误。不要用异常代替错误,更不要用来控制流程。在极个别的情况下,才使用Go中引入的Exception处理:defer, panic, recover。
 

一. defer 用法

defer的特性: 在函数返回之前, 调用defer函数的操作, 简化函数的清理工作.

在初接触到go时, 就被defer吸引住了,但是在使用defer关键字的时候,还是得注意这些:

1. 在defer表达式确定的时候,defer修饰的函数(后面统称为defered函数)的参数也就确定了

package main

import (
"fmt"
) func main() {
g()
} func g() {
i := 0
defer fmt.Println(i)
i++
return
}
-------output-------
0

2. 函数内可以有多个defered函数,但是这些defered函数在函数返回时遵守后进先出的原则

package main
import "fmt"

func main() {
g()
} func g() {
for i := 0; i<4; i++ {
defer fmt.Println(i)
}
}
-------output-------
3
2
1
0

3. 函数命名的返回值跟defered函数一起使用
函数的返回值有可能被defer更改,本质原因是return xxx语句并不是一条原子指令,执行过程是: 保存返回值(若有)-->执行defer(若有)-->执行return跳转。

func f() (result int) {
defer func() {
result++
}()
return
} func g() (r int) {
t :=
defer func() {
t = t +
}()
return t
} func h() (r int) {
defer func(r int) {
r = r +
}(r)
return
}
-------output-------
0

对于defered函数跟函数命名返回值一块使用的情况, 当无法判断返回值的时候, 需要对函数进行变形.

func f(result int) {
result = 0
func () {
result++
}()
return
}
-------output-------
1

func g() (r int) {
t :=
r = t
func () {
t = t +
}
return
}
-------output-------
5
func h() (r int) {
r =
func (r int) {
r = r +
}(r)
return
}
-------output-------
1

在func(r int) {...}中,由于r是以值传递的方式进行的, 所以r的值不会改变。

注意:
  1. 申请资源后最好立即使用defer关闭资源。

二. panic用法

panic用法挺简单的, 其实就是throw exception。

panic是golang的内建函数,panic会中断函数F的正常执行流程, 从F函数中跳出来, 跳回到F函数的调用者. 对于调用者来说, F看起来就是一个panic, 所以调用者会继续向上跳出, 直到当前goroutine返回. 在跳出的过程中, 进程会保持这个函数栈. 当goroutine退出时, 程序会crash。

要注意的是, F函数中的defered函数会正常执行, 按照上面defer的规则。

同时引起panic除了我们主动调用panic之外, 其他的任何运行时错误, 例如数组越界都会造成panic

看下面一个例子

package main

import (
"fmt"
) func main() {
test()
} func test() {
defer func() { fmt.Println("打印前") }()
defer func() { fmt.Println("打印中") }()
defer func() { fmt.Println("打印后") }()
panic("触发异常")
fmt.Println("test")
}
-------output-------
打印后 
打印中
打印前
panic: 触发异常 goroutine [running]:
main.test()
    D:/Go_Path/go/src/logDemo/main.go: +0x98
    main.main() D:/Go_Path/go/src/logDemo/main.go: +0x27
exit status

三. recover 用法
recover也是golang的一个内建函数, 其实就是try catch。

不过需要注意的是:

  1. recover如果想起作用的话, 必须在defered函数中使用。
  2. 在正常函数执行过程中,调用recover没有任何作用, 他会返回nil。如这样:fmt.Println(recover()) 。
  3. 如果当前的goroutine panic了,那么recover将会捕获这个panic的值,并且让程序正常执行下去。不会让程序crash。

func main() {
fmt.Println("c")
defer func() { // 必须要先声明defer,否则不能捕获到panic异常
fmt.Println("d")
if err := recover(); err != nil {
fmt.Println(err) // 这里的err其实就是panic传入的内容
}
fmt.Println("e")
}()
f() //开始调用f
fmt.Println("f") //这里开始下面代码不会再执行
} func f() {
fmt.Println("a")
panic("异常信息")
fmt.Println("b") //这里开始下面代码不会再执行
}
-------output-------
c
a
d
异常信息
e

参考链接
  1. defer关键字
  2. Golang中defer、return、返回值之间执行顺序的坑

Golang 入门系列(十四)defer, panic和recover用法的更多相关文章

  1. Golang 入门系列(十) mysql数据库的使用

    之前,已经讲过一些Golang的基础的东西,感兴趣的可以看看以前的文章,https://www.cnblogs.com/zhangweizhong/category/1275863.html, 今天简 ...

  2. Golang 入门系列(四)如何理解interface接口

    前面讲了很多Go 语言的基础知识,包括go环境的安装,go语言的语法等,感兴趣的朋友,可以先看看之前的文章.https://www.cnblogs.com/zhangweizhong/category ...

  3. GOLANG错误处理最佳方案errors wrap, Defer, Panic, and Recover

    Simple error handling primitives:        https://github.com/pkg/errors Defer, Panic, and Recover:    ...

  4. 无废话ExtJs 入门教程十四[文本编辑器:Editor]

    无废话ExtJs 入门教程十四[文本编辑器:Editor] extjs技术交流,欢迎加群(201926085) ExtJs自带的编辑器没有图片上传的功能,大部分时候能够满足我们的需要. 但有时候这个功 ...

  5. Bootstrap入门(十四)组件8:媒体对象

    Bootstrap入门(十四)组件8:媒体对象 这是一个抽象的样式,用以构建不同类型的组件,这些组件都具有在文本内容的左或右侧对齐的图片(就像博客评论或 Twitter 消息等). 1.基本样式 2. ...

  6. MyBatis基础入门《十四》ResultMap子元素(association )

    MyBatis基础入门<十四>ResultMap子元素(association ) 1. id: >> 一般对应数据库中改行的主键ID,设置此项可以提高Mybatis的性能 2 ...

  7. struts2官方 中文教程 系列十四:主题Theme

    介绍 当您使用一个Struts 2标签时,例如 <s:select ..../>  在您的web页面中,Struts 2框架会生成HTML,它会显示外观并控制select控件的布局.样式和 ...

  8. RabbitMQ入门教程(十四):RabbitMQ单机集群搭建

    原文:RabbitMQ入门教程(十四):RabbitMQ单机集群搭建 版权声明:本文为博主原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明. 本文链接:https://b ...

  9. golang 自学系列(四)——debug for vscode

    golang 自学系列(四)--(调试)VSCode For Debug 这里如何装 vscode 我就不说了 这里如何在 vscode 正常写代码我也不说了 在能正常用 vscode 写 go 语言 ...

随机推荐

  1. 线程池ThreadPoolExecutor的使用方法

    方法我们通过继承Thread类和实现runnable接口或者callable接口三种方式实现. 继承Thread类实际上也是实现了runnable接口,被继承的类主要是实现run()方法,通过star ...

  2. k8s 获取 Pod ip 添加到环境变量

    0x00 事件 有一个需要将 Pod 自身的 ip 地址添加到环境变量的需求,可以在 yaml 文件的 env 中这样设置: env: - name: POD_OWN_IP_ADDRESS value ...

  3. Precision,Recall,F1的计算

    Precision又叫查准率,Recall又叫查全率.这两个指标共同衡量才能评价模型输出结果. TP: 预测为1(Positive),实际也为1(Truth-预测对了) TN: 预测为0(Negati ...

  4. yum运行报错:File "/usr/libexec/urlgrabber-ext-down", line 28

    [root@sdw1 bin]# vim /usr/libexec/urlgrabber-ext-down 再次执行yum命令,正常下载

  5. Android Studio 2.2 NDK开发环境搭建

    转载请标明出处:http://blog.csdn.net/shensky711/article/details/52763192 本文出自: [HansChen的博客] Android应用程序使用ND ...

  6. 【开发工具 - Git】之本地项目托管到远程仓库

    这里所说的“本地项目托管到远程仓库”,说的是:例如,我们在本地有一个写了很长时间的项目,现在想要托管到GitHub或码云上进行版本控制. 这个过程大致需要以下几个步骤: (1)在本地初始化Git项目本 ...

  7. 04-kubernetes 资源清单定义入门

    目录 资源对象 创建资源的方法 清单帮助命令 创建测试清单 资源的三种创建方式 资源对象 workload:Pod, ReplicaSet, Deployment, StatefulSet, Daem ...

  8. VS #region

    1.C# 预处理指令 #region使您得以在使用Visual Studio代码编辑器的大纲显示功能时指定可展开或折叠的代码块.    #region   name    其中:name      希 ...

  9. Beautifulsoup模块基础详解

    Beautifulsoup模块 官方中文文档 Beautifulsoup官方中文文档 介绍 Beautiful Soup 是一个可以从HTML或XML文件中提取数据的Python库.它能够通过你喜欢的 ...

  10. MySQL主从介绍、配置主从、测试主从同步

    6月28日任务 说明:有不少同学不能一次性把实验做成功,这是因为还不熟悉,建议至少做3遍17.1 MySQL主从介绍17.2 准备工作17.3 配置主17.4 配置从17.5 测试主从同步有的同学,遇 ...