Go圣经-学习笔记之defer和异常处理
2019独角兽企业重金招聘Python工程师标准>>>
上一篇 Go圣经-学习笔记之函数值(二)
下一篇 Go圣经-学习笔记之方法
可变参数
形参数量可变的函数称为可变参数函数。使用最多的可变参数函数标准库:fmt
。
在声明可变参数函数时,需要在参数列表的最后一个参数类型之前加上省略符号...
。
func 函数名(t Type1, t Type2, tn ...TypeN) 返回参数列表 {}// DEMO
func sum(x, y ...int) int {count:=xfor _, elem:= range y {count+=elem}return count
}fmt.Println(sum(1,2,3,4,5,6,7,8)) // 使用方法1elems:=[]int{2,3,4,5,6,7,8}
fmt.Println(sum(1, elems...) // 使用方法2
defer函数
defer表示函数退出时,栈内的函数列表退栈执行。这个主要介绍defer和return之间的关系。
func Incr() (i int) {defer func(){i++ }()return 1
}fmt.Println(Incr()) // 打印值i = 1 ?
实际上defer和return的执行顺序是没有什么问题的。先执行defer,然后再return。重点是 return xx。前面章节说过,它不是一个原子操作。分解动作为:
func Incr() (i int) {defer func() {i++}()i=1return
}
第二个是我在写Go服务端时的一个小经验,首先说一下背景,我们一般想做日志追踪或者请求链的调用追踪,看看程序执行到哪个步骤然后出错了。这时,我们一般会这样做:
func AddSaleOrder(so *SaleOrder, o *orm.Ormer) (retCode int, err error) {......Logger.Info("[%d] enter AddSaleOrder.", so.SaleOrderId)defer Logger.Info("[%d] left AddSaleOrder.", so.SaleOrderId)......return
}
但是为了懒不想写两句,或者节约代码长度什么的。然后就采用了写出了下面这种方式:
func bigSlowOp() {defer TraceLog("bigSlowOp")()fmt.Println("hello,world")time.Sleep(3 * time.Second)return
}func TraceLog(methodName string, params ...interface{}) func() {start := time.Now()fmt.Printf("[%v] enter %s\n", params, methodName)return func() {fmt.Printf("[time: %s | %v] left %s\n", time.Since(start), params, methodName)}
}func main() {bigSlowOp()return
}
// 输出结果
/*
[[]] enter bigSlowOp
hello,world
[time: 3.000241212s | []] left bigSlowOp
*/
那么,我们以后只需要写defer TraceLog(方法名,参数列表)()
就OK了
defer语句经常用于处理成对的操作,如打开、关闭、连接、断开连接、加锁、释放锁等,无论函数是正常执行完成,还是提前退出或者panic,defer堆栈里的函数列表都会执行。那么资源也可以释放。
同时,我们也要注意引入defer,如果不注意,可能会带来资源泄露问题:
for _, filename:= range filenames{f, err := os.Open(filename)if err !=nil{return}defer f.Close() // 因为f的生命周期一直在for循环内,所以defer在退出之前不会执行。如果文件列表过大,就是造成文件描述符大量泄露,如果是网络,则会出现"connection peer by peer"的相关错误。
}// 解决方案:使f变量的生命周期缩短,和for循环的执行周期分离开
func doFile(filename string) error {f, err := os.Open(filename)if err !=nil{return err}defer f.Close()return nil
}for _, filename:= range filenames {err := doFile(filename)
}
一旦有生命周期的障碍,首先想到函数体执行的生命周期。
Panic异常
一般而言程序在运行过程中,发生了数组越界,空指针引用错误等,这些错误会引起panic异常。当发生panic时,程序会中断运行,并立即在Goroutine中被延迟的函数。随后并输出日志信息,包括发生错误值,以及上下文调用栈。
但是并不是所有的panic都来自运行时,开发者也可以直接调用panic函数引发panic异常;panic接收任何参数。为了方便诊断问题,标准库runtime允许开发者输出堆栈信息。例如:
func main(){defer printStack()f(3)
}func printStack() {var buf [4096]byteruntime.Stack(buf[:], false)os.Stdout.Write(buf[:n])
}
Recover捕获异常
通常来说,不应该对panic异常做任何处理。让异常尽量早暴露早修复,提高软件的可用性。但有时也需要从异常恢复,至少让程序崩溃前做一些操作,比如: 如果网络服务端挂掉,如果服务端不做任何处理,直接panic,则客户端迟迟得不到服务端的响应,影响用户体验。
如果在defer内调用了内置函数recover,并且定义该defer的函数发生了panic,recover会使程序从panic恢复,并返回panic value。导致panic异常的函数不会再运行,但正常返回。在未发生panic时,调用recover会返回nil。
这里要说明一下,至于panic被哪里的recover捕获,或者不会捕获,可以参考这篇文章: panic和recover工作原理
后续我会通过雨痕老师的Go源码分析书籍,深入分析panic和recover,这样更容易深入地理解。
转载于:https://my.oschina.net/u/3287304/blog/1556245
Go圣经-学习笔记之defer和异常处理相关推荐
- Go圣经-学习笔记目录
2019独角兽企业重金招聘Python工程师标准>>> 第一章 入门 Go圣经-学习笔记入门 Go圣经-学习笔记绪论 Go圣经-学习笔记入门-面试题 Go圣经-学习笔记入门bufio ...
- Go圣经-学习笔记之复合类型(二)
2019独角兽企业重金招聘Python工程师标准>>> 上一篇 Go圣经-学习笔记之复合类型 下一篇 Go圣经-学习笔记之复合数据结构(三) map介绍和简单使用 map是一种无序的 ...
- 《mysql入门圣经》_Go圣经-学习笔记之并发循环
首先说一个,本来上一篇文章应该是, Go圣经-学习笔记之Channel和Goroutine.写了很长一段,结果被有道云笔记TMD坑惨了,服务掉了,不能拷贝,不能保存.这篇文章就丢了.如果以后有时间,我 ...
- 2022Java学习笔记七十三(异常处理:运行时异常、编译时异常、异常的默认处理的流程)
2022Java学习笔记七十三(异常处理:运行时异常.编译时异常.异常的默认处理的流程) 一.异常体系 1.Exception:java.lang包下,称为异常类,它表示程序本身可以处理的问题 2.R ...
- go channel 缓冲区最大限制_GO语言圣经学习笔记(八)Goroutines和Channels
奋斗鸭!Day97 知识点 goroutinue 基本用法 golang非常深度的简化了goroutinue的使用方法,异常简单,门槛降低很多 // goroutinue 使用非常简单go f() G ...
- 【学习笔记】JAVA基础——异常处理部分
文章目录 前言 简介 一. try.catch与finally ① try && catch ② finally ③ throws 补充:JVM 相关 二. 异常的分类 ① 分类解释与 ...
- 【Go学习】go语言圣经学习笔记
目录 前言 入门 前言 想扎扎实实的看看书,跟着书的目录结构走,记录看书笔记 The Go Programming Language Go语言圣经(中文版) 入门
- 《疯狂Java讲义》学习笔记(十)异常处理
2019独角兽企业重金招聘Python工程师标准>>> 0.Java的异常体系 1.异常概述 异常机制已经成为判断一门编程语言是否成熟的标准,目前主流的编程语言都提供了成熟的异常机制 ...
- 【Java学习笔记五】Java异常处理
异常通常分为三类: 程序可控制的异常:一般是可预见的错误,不是致命的.例如:除数为0,数组下标越界. 程序不可控制的的异常:这种异常往往是致命的,但是系统可以预见的.例如:系统栈溢出. 人为异常 当系 ...
最新文章
- System.Insert - 插入字符串
- Linux C++多线程同步的四种方式
- seaborn.heatmap概述
- 淘宝客静态单页_单页应用程序的Spring Boot静态Web资源处理
- Linux程序选择boy糊者girl,linux脚本程序练习-Go语言中文社区
- 第一章 软件工程概论
- 计算机接口及应用技术,计算机接口技术及应用 第9讲 控制网络技术(2 现场总线).pdf...
- PHP中Trait详解及其应用
- 关于可达矩阵的O(N*N)算法和强分图的O(E)算法
- Java开发必备软件安装大全(建议学生党初学Java开发收藏)
- 如何提高计算机软件的性能,如何提高计算机性能?
- smartsvn 忽略文件夹_设置SVN忽略文件和目录(文件夹)
- 计算机环境变量怎么恢复默认,环境变量怎么还原
- 未明学院:管培生刚入职就被裁?校招的管培生真的那么高大上吗?
- 如何使用 ABAP 代码发送带有 PDF 附件的电子邮件
- 关于本人的网络地址请移步简书
- Java汉字转换拼音工具类
- [附源码]java毕业设计校园拓展活动管理系统
- 腾讯、抖音回应被判侵害用户信息;美团禁用支付宝;苹果称今年新iPhone将推迟数周发布 | EA周报...
- mybatis SQL打印插件