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和异常处理相关推荐

  1. Go圣经-学习笔记目录

    2019独角兽企业重金招聘Python工程师标准>>> 第一章 入门 Go圣经-学习笔记入门 Go圣经-学习笔记绪论 Go圣经-学习笔记入门-面试题 Go圣经-学习笔记入门bufio ...

  2. Go圣经-学习笔记之复合类型(二)

    2019独角兽企业重金招聘Python工程师标准>>> 上一篇 Go圣经-学习笔记之复合类型 下一篇 Go圣经-学习笔记之复合数据结构(三) map介绍和简单使用 map是一种无序的 ...

  3. 《mysql入门圣经》_Go圣经-学习笔记之并发循环

    首先说一个,本来上一篇文章应该是, Go圣经-学习笔记之Channel和Goroutine.写了很长一段,结果被有道云笔记TMD坑惨了,服务掉了,不能拷贝,不能保存.这篇文章就丢了.如果以后有时间,我 ...

  4. 2022Java学习笔记七十三(异常处理:运行时异常、编译时异常、异常的默认处理的流程)

    2022Java学习笔记七十三(异常处理:运行时异常.编译时异常.异常的默认处理的流程) 一.异常体系 1.Exception:java.lang包下,称为异常类,它表示程序本身可以处理的问题 2.R ...

  5. go channel 缓冲区最大限制_GO语言圣经学习笔记(八)Goroutines和Channels

    奋斗鸭!Day97 知识点 goroutinue 基本用法 golang非常深度的简化了goroutinue的使用方法,异常简单,门槛降低很多 // goroutinue 使用非常简单go f() G ...

  6. 【学习笔记】JAVA基础——异常处理部分

    文章目录 前言 简介 一. try.catch与finally ① try && catch ② finally ③ throws 补充:JVM 相关 二. 异常的分类 ① 分类解释与 ...

  7. 【Go学习】go语言圣经学习笔记

    目录 前言 入门 前言 想扎扎实实的看看书,跟着书的目录结构走,记录看书笔记 The Go Programming Language Go语言圣经(中文版) 入门

  8. 《疯狂Java讲义》学习笔记(十)异常处理

    2019独角兽企业重金招聘Python工程师标准>>> 0.Java的异常体系 1.异常概述 异常机制已经成为判断一门编程语言是否成熟的标准,目前主流的编程语言都提供了成熟的异常机制 ...

  9. 【Java学习笔记五】Java异常处理

    异常通常分为三类: 程序可控制的异常:一般是可预见的错误,不是致命的.例如:除数为0,数组下标越界. 程序不可控制的的异常:这种异常往往是致命的,但是系统可以预见的.例如:系统栈溢出. 人为异常 当系 ...

最新文章

  1. System.Insert - 插入字符串
  2. Linux C++多线程同步的四种方式
  3. seaborn.heatmap概述
  4. 淘宝客静态单页_单页应用程序的Spring Boot静态Web资源处理
  5. Linux程序选择boy糊者girl,linux脚本程序练习-Go语言中文社区
  6. 第一章 软件工程概论
  7. 计算机接口及应用技术,计算机接口技术及应用 第9讲 控制网络技术(2 现场总线).pdf...
  8. PHP中Trait详解及其应用
  9. 关于可达矩阵的O(N*N)算法和强分图的O(E)算法
  10. Java开发必备软件安装大全(建议学生党初学Java开发收藏)
  11. 如何提高计算机软件的性能,如何提高计算机性能?
  12. smartsvn 忽略文件夹_设置SVN忽略文件和目录(文件夹)
  13. 计算机环境变量怎么恢复默认,环境变量怎么还原
  14. 未明学院:管培生刚入职就被裁?校招的管培生真的那么高大上吗?
  15. 如何使用 ABAP 代码发送带有 PDF 附件的电子邮件
  16. 关于本人的网络地址请移步简书
  17. Java汉字转换拼音工具类
  18. [附源码]java毕业设计校园拓展活动管理系统
  19. 腾讯、抖音回应被判侵害用户信息;美团禁用支付宝;苹果称今年新iPhone将推迟数周发布 | EA周报...
  20. mybatis SQL打印插件

热门文章

  1. [图解教程]Axis2与Eclipse整合开发Web Service之二:WSDL逆向生成服务端
  2. 华为的创新——计划制定和调整水平
  3. 计算机网络课程优秀备考PPT之第五章网络层(五)
  4. Windows系统 配置Java的JDK环境变量
  5. Apache的性能优化
  6. Sqlite3支持的数据类型 日期函数以及相关 函数
  7. 维基链超级节点竞选的具体细节有哪些?
  8. 比特币现金vs莱特币,谁将夺得小额支付市场?
  9. mysql触发器trigger
  10. (1)虚拟机管理——在微软云Azure新门户创建虚拟机