①error接口

Go语言中的error类型实际上是抽象了Error()方法的error接口

  1. type error interface {
  2. Error() string
  3. }

Go语言使用该接口进行标准的错误处理。

对于大多数函数,如果要返回错误,大致上都可以定义为如下模式,将error作为多种返回
值中的最后一个,但这并非是强制要求:

  1. func Foo(param int)(n int, err error) {
  2. // ...
  3. }

调用时的代码建议按如下方式处理错误情况:

  1. n, err := Foo()
  2. if err != nil {
  3. // 错误处理
  4. } else {
  5. // 使用返回值n
  6. }

看下面的例子综合了一下error接口的用法:

  1. package main
  2.  
  3. import (
  4. "fmt"
  5. )
  6.  
  7. //自定义错误类型
  8. type ArithmeticError struct {
  9. error //实现error接口
  10. }
  11.  
  12. //重写Error()方法
  13. func (this *ArithmeticError) Error() string {
  14. return "自定义的error,error名称为算数不合法"
  15. }
  16.  
  17. //定义除法运算函数
  18. func Devide(num1, num2 int) (rs int, err error) {
  19. if num2 == {
  20. return , &ArithmeticError{}
  21. } else {
  22. return num1 / num2, nil
  23. }
  24. }
  25. func main() {
  26. var a, b int
  27. fmt.Scanf("%d %d", &a, &b)
  28.  
  29. rs, err := Devide(a, b)
  30. if err != nil {
  31. fmt.Println(err)
  32. } else {
  33. fmt.Println("结果是:", rs)
  34. }
  35. }

运行,输入参数5 2(正确的情况):

  1. 结果是:

若输入5 0(产生错误的情况):

  1. 自定义的error,error名称为算数不合法

通过上面的例子可以看出error类型类似于Java中的Exception类型,不同的是Exception必须搭配throw和catch使用。

②defer--延迟语句

在Go语言中,可以使用关键字defer向函数注册退出调用,即主调函数退出时,defer后的函数才会被调用。
defer语句的作用是不管程序是否出现异常,均在函数退出时自动执行相关代码。(相当于Java中的finally

当函数执行到最后时,这些defer语句会按照逆序执行,最后该函数返回。

例如:

  1. package main
  2.  
  3. import (
  4. "fmt"
  5. )
  6.  
  7. func main() {
  8. for i := ; i < ; i++ {
  9. defer fmt.Println(i)
  10. }
  11. }

其执行结果为:

  1.  

defer语句在声明时被加载到内存(多个defer语句按照FIFO原则) ,加载时记录变量的值,而在函数返回之后执行,看下面的例子:

例子1:defer语句加载时记录值

  1. func f1() {
  2. i :=
  3. defer fmt.Println(i) //实际上是将fmt.Println(0)加载到内存
  4. i++
  5. return
  6. }
  7. func main() {
  8. f1()
  9. }

其结果显然是0

例子2:在函数返回后执行

  1. func f2() (i int) {
  2. var a int =
  3. defer func() {
  4. a++
  5. fmt.Println("defer内部", a)
  6. }()
  7. return a
  8. }
  9. func main() {
  10. fmt.Println("main中", f2())
  11. }

其结果是

  1. defer内部
  2. main

例子3:defer语句会读取主调函数的返回值,并对返回值赋值.(注意和例子2的区别)

  1. func f3() (i int) {
  2. defer func() {
  3. i++
  4. }()
  5. return
  6. }
  7. func main() {
  8. fmt.Println(f3())
  9. }

其结果竟然是2.

通过上面的几个例子,自然而然会想到用defer语句做清理工作,释放内存资源(这样你再也不会为Java中的try-catch-finally层层嵌套而苦恼了)

例如关闭文件句柄:

  1. srcFile,err := os.Open("myFile")
  2. defer srcFile.Close()

关闭互斥锁:

  1. mutex.Lock()
  2. defer mutex.Unlock()

上面例子中defer语句的用法有两个优点:

1.让设计者永远也不会忘记关闭文件,有时当函数返回时常常忘记释放打开的资源变量。

2.将关闭和打开靠在一起,程序的意图变得清晰很多。

下面看一个文件复制的例子:

  1. package main
  2.  
  3. import (
  4. "fmt"
  5. "io"
  6. "os"
  7. )
  8.  
  9. func main() {
  10. copylen, err := copyFile("dst.txt", "src.txt")
  11. if err != nil {
  12. return
  13. } else {
  14. fmt.Println(copylen)
  15. }
  16.  
  17. }
  18.  
  19. //函数copyFile的功能是将源文件sec的数据复制给dst
  20. func copyFile(dstName, srcName string) (copylen int64, err error) {
  21. src, err := os.Open(srcName)
  22. if err != nil {
  23. return
  24. }
  25. //当return时就会调用src.Close()把源文件关闭
  26. defer src.Close()
  27. dst, err := os.Create(dstName)
  28. if err != nil {
  29. return
  30. }
  31. //当return是就会调用src.Close()把目标文件关闭
  32. defer dst.Close()
  33. return io.Copy(dst, src)
  34. }

可以看到确实比Java简洁许多。

③panic-recover运行时异常处理机制

Go语言中没有Java中那种try-catch-finally结构化异常处理机制,而使用panic()函数答题throw/raise引发错误,

然后在defer语句中调用recover()函数捕获错误,这就是Go语言的异常恢复机制——panic-recover机制

两个函数的原型为:

  1. func panic(interface{})//接受任意类型参数 无返回值
  2. func recover() interface{}//可以返回任意类型 无参数

一定要记住,你应当把它作为最后的手段来使用,也就是说,你的代码中应当没有,或者很少有panic的东西。这是个强大的工具,请明智地使用
它。那么,我们应该如何使用它呢?

panic()
是一个内建函数,可以中断原有的控制流程,进入一个令人panic(恐慌即Java中的异常)的流程中。当函数F调用panic,函数F的执行被中
断,但是F中的延迟函数(必须是在panic之前的已加载的defer)会正常执行,然后F返回到调用它的地方。在调用的地方,F的行为就像调用了panic。这一
过程继续向上,直到发生panic的goroutine中所有调用的函数返回,此时程序退出。异常可以直接调用panic产
生。也可以由运行时错误产生,例如访问越界的数组。

recover()
是一个内建的函数,可以让进入令人恐慌的流程中的goroutine恢复过来。recover仅在延迟函数中有效。在正常
的执行过程中,调用recover会返回nil,并且没有其它任何效果。如果当前的goroutine陷入panic,调用
recover可以捕获到panic的输入值,并且恢复正常的执行。

一般情况下,recover()应该在一个使用defer关键字的函数中执行以有效截取错误处理流程。如果没有在发生异常的goroutine中明确调用恢复

过程(使用recover关键字),会导致该goroutine所属的进程打印异常信息后直接退出。

这里结合自定义的error类型给出一个使用panic和recover的完整例子:

  1. package main
  2.  
  3. import (
  4. "fmt"
  5. )
  6.  
  7. //自定义错误类型
  8. type ArithmeticError struct {
  9. error
  10. }
  11.  
  12. //重写Error()方法
  13. func (this *ArithmeticError) Error() string {
  14. return "自定义的error,error名称为算数不合法"
  15. }
  16.  
  17. //定义除法运算函数***这里与本文中第一幕①error接口的例子不同
  18. func Devide(num1, num2 int) int {
  19. if num2 == {
  20. panic(&ArithmeticError{}) //当然也可以使用ArithmeticError{}同时recover等到ArithmeticError类型
  21. } else {
  22. return num1 / num2
  23. }
  24. }
  25. func main() {
  26. var a, b int
  27. fmt.Scanf("%d %d", &a, &b)
  28.  
  29. defer func() {
  30. if r := recover(); r != nil {
  31. fmt.Printf("panic的内容%v\n", r)
  32. if _, ok := r.(error); ok {
  33. fmt.Println("panic--recover()得到的是error类型")
  34. }
  35. if _, ok := r.(*ArithmeticError); ok {
  36. fmt.Println("panic--recover()得到的是ArithmeticError类型")
  37. }
  38. if _, ok := r.(string); ok {
  39. fmt.Println("panic--recover()得到的是string类型")
  40. }
  41. }
  42. }()
  43.  
  44. rs := Devide(a, b)
  45. fmt.Println("结果是:", rs)
  46. }

其执行的结果为:

使用与上面相同的测试数据,输入5 2得:

  1. 结果是:

输入5 0得:

  1. panic的内容自定义的error,error名称为算数不合法
  2. panic--recover()得到的是error类型
  3. panic--recover()得到的是ArithmeticError类型

可见已将error示例程序转换为了Java中的用法,但是在大多数程序中使用error处理的方法较多。

需要注意的是:defer语句定义的位置 如果defer放在了

  1. rs := Devide(a, b)语句之后,defer将没有机会执行即下面的程序失效:
  1. rs := Devide(a, b)
  2. defer func() {
  3. if r := recover(); r != nil {
  4. fmt.Printf("panic的内容%v\n", r)
  5. if _, ok := r.(error); ok {
  6. fmt.Println("panic--recover()得到的是error类型")
  7. }
  8. if _, ok := r.(*ArithmeticError); ok {
  9. fmt.Println("panic--recover()得到的是ArithmeticError类型")
  10. }
  11. if _, ok := r.(string); ok {
  12. fmt.Println("panic--recover()得到的是string类型")
  13. }
  14. }
  15. }()
  1. 因为在在陷入panic之前defer语句没有被加载到内存,而在执行panic时程序被中断,因而无法执行defer语句。

【Go语言】错误与异常处理机制的更多相关文章

  1. 【C++】异常简述(一):C语言中的异常处理机制

    人的一生会遇到很多大起大落,尤其是程序员. 程序员写好的程序,论其消亡形式无非三种:无疾而终.自杀.他杀. 当然作为一名程序员,最乐意看到自己写的程序能够无疾而终,因此尽快的学习异常处理机制是非常重要 ...

  2. ThinkPHP5.0源码学习之注册错误和异常处理机制

    在base.php文件中,用一句代码\think\Error::register();实现错误和异常处理机制的注册. // 注册错误和异常处理机制 \think\Error::register(); ...

  3. PHP 注册错误和异常处理机制

    注册错误和异常处理机制有三个PHP函数需要学习 1. register_shutdown_function('Bootstrap\Library\Frame::fatalError'); 2. set ...

  4. C语言中的异常处理机制

    #define try if(!setjmp(Jump_Buffer)) 返回try现场后重新执行判断,所以有两次执行. http://blog.csdn.net/tian_dao_chou_qin/ ...

  5. [R]R语言里的异常处理与错误控制

    之前一直只是在写小程序脚本工具,几乎不会对异常和错误进行控制和处理. 随着脚本结构和逻辑更复杂,脚本输出结果的准确性验证困难,同时已发布脚本的维护也变得困难.所以也开始考虑引入异常处理和测试工具的事情 ...

  6. php5和php7的异常处理机制 ----thinkphp5 异常处理的分析

    1.php异常和错误 在其他语言中,异常和错误是有区别的,但是PHP,遇见自身错误时,会触发一个错误,而不是跑出异常.并且,php大部分情况,都会触发错误,终止程序执行,在php5中,try catc ...

  7. c语言异常处理机制

    异常处理机制:setjmp()函数与longjmp()函数 C标准库提供两个特殊的函数:setjmp() 及 longjmp(),这两个函数是结构化异常的基础,正是利用这两个函数的特性来实现异常. 所 ...

  8. [转贴]从零开始学C++之异常(一):C语言错误处理方法、C++异常处理方法(throw, try, catch)简介

    一.C语言错误处理方法 1.返回值(if … else语句判断错误) 2.errno(linux 系统调用) 3.goto语句(函数内局部跳转) 4.setjmp.longjmp(Do not use ...

  9. php错误处理和php异常处理机制

    php错误处理  当我们开发程序时,有时候程序出现了问题,我们就可以用以下几种办法找出错误.  开发阶段:开发时输出所有的错误报告,有利于我们进行程序调试  运行阶段:我们不要让程序输出任何一种错误报 ...

随机推荐

  1. php mysql PDO基本操作

    <?php $dbh = new PDO('mysql:host=localhost;dbname=localhost', 'root', ''); $dbh->setAttribute( ...

  2. linux下搭建属于自己的博客(WordPress安装)

    转自:http://www.cnblogs.com/xiaofengkang/archive/2011/11/16/2251608.html WordPress简介 WordPress 是一种使用 P ...

  3. phpexecel 导入导出,格式

    1.日期时间合并到c中 =a1 &b1 或 =a1 + b1 这些都是运算符 2.此时c1的值是这条公式,而并不是公式运算的结果 复制c,粘贴到d,选择粘贴值 3.此时c是时间日期格式的,如需 ...

  4. FFmpeg与libx264 x264接口源代码简单分析

    源代码位于“libavcodec/libx264.c”中.正是有了这部分代码,使得FFmpeg可以调用libx264编码H.264视频.  从图中可以看出,libx264对应的AVCodec结构体ff ...

  5. css3写箭头

    左箭头 .left-arrow { position: absolute; left: 6%; top: 31%; overflow: hidden; zoom:; width: 0.4rem; he ...

  6. js-DOM2,表单脚本

    DOM2: 1.DOM2中:创建一个完整的HTML文档 document.implementation.createHTMLDocument("new Doc"); alert(h ...

  7. 解决ie8和ie7显示不一致

    解决ie8和ie7显示不一致 当使用 Microsoft Internet Explorer 8 Beta 1 版本时,可能会遇到以下问题之一: • 网页布局不整齐 • 文本或图像重叠 • JavaS ...

  8. [bzoj3224]普通平衡树/3223文艺平衡树

    这是一道很普通的题.. 最近花了很多时间来想要去干什么,感觉自己还是太拿衣服 做这道题是因为偶尔看到了lavender的blog和她的bzoj早期AC记录,就被题目深深地吸引到了,原因有二: 自己sp ...

  9. daemontools管理fast-fail的zookeeper

    daemontools项目:http://cr.yp.to/daemontools.html 1.安装daemontools mkdir /package /package cd /package w ...

  10. BZOJ2434 [Noi2011]阿狸的打字机(AC自动机 + fail树 + DFS序 + 线段树)

    题目这么说的: 阿狸喜欢收藏各种稀奇古怪的东西,最近他淘到一台老式的打字机.打字机上只有28个按键,分别印有26个小写英文字母和'B'.'P'两个字母.经阿狸研究发现,这个打字机是这样工作的: 输入小 ...