继续浏览精彩内容
慕课网APP
程序员的梦工厂
打开
继续
感谢您的支持,我会继续努力的
赞赏金额会直接到老师账户
将二维码发送给自己后长按识别
微信支付
支付宝支付

Go语言开发(七)、Go语言错误处理

holdtom
关注TA
已关注
手记 1846
粉丝 240
获赞 991


Go语言开发(七)、Go语言错误处理

一、defer延迟函数

1、defer延迟函数简介

defer在声明时不会立即执行,而是在defer所在的函数return后,再按照FILO(先进后出)的原则依次执行每一个defer,一般用于异常处理、释放资源、清理数据、记录日志等。

每次defer语句执行时,defer修饰函数的返回值和参数取值会照常进行计算和保存,但是defer修饰的函数不会执行。等到上一级函数返回前,会按照defer的声明顺序倒序执行全部defer的函数。defer所修饰函数的任何返回值都会被丢弃。

如果一个defer所修饰函数的值为nil,则defer的函数会在函数执行时panic(异常),而不会在defer语句执行时panic。defer所修饰函数的上一级函数即使抛出异常,defer所修饰函数也会被执行的,确保资源被合法释放。

defer延迟函数使用示例如下:

package main

import "fmt"

func deferTest() {

   defer fmt.Println(1)

   defer fmt.Println(2)

   fmt.Println(3)

   for i := 100; i < 105; i++ {

      defer fmt.Println(i) //执行defer时进行参数计算

   }

}

func main() {

   deferTest()

}

// output:

3

104

103

102

101

100

2

1

2、defer延迟函数应用

A、简化资源回收

mu.Lock() 

defer mu.Unlock()

defer 有一定的开销, 为了节省性能可以避免使用的defer 

B、捕获panic异常

Go语言中,panic用于抛出异常,,recover用于捕获异常。

recover只能在defer语句中使用,直接调用recover是无效的。

package main

import "fmt"

func deferRecover(){

   defer func () {

      if r := recover(); r != nil {

         fmt.Println("recover")

      }

   }()

   fmt.Println("exception will be happen")

   panic("exception has happped.")

   fmt.Println("return normally")

}

func main() {

   deferRecover()

}

C、修改返回值

defer可以用于在 return 后修改函数的返回值。

package main

import "fmt"

func deferReturn(a,b int)(sum int){

   defer func(){

      sum += 100

   }()

   sum = a + b

   return sum

}

func main() {

   sum := deferReturn(1,6)

   fmt.Println(sum)//107

}

D、安全回收资源

func set(mu *sync.Mutex, arr []int, i, v int) {

   mu.Lock()

   defer mu.Unlock()

   arr[i] = v

}

如果运行时抛出切片越界异常,可以保证mu.Unlock()被调用。

二、错误处理

1、错误处理简介

Go语言通过内置的错误接口提供了简单的错误处理机制。

error类型是一个接口类型,定义如下:

type error interface {

    Error() string}

Golang中引入error接口类型作为错误处理的标准模式,如果函数要返回错误,则返回值类型列表中肯定包含error。

2、错误处理使用

package main

import (

   "fmt"

   "errors"

)

//定义一个DivideError类型

type DivideError struct {

   dividee int

   divider int

}

//实现error接口

func (err *DivideError) Error() error{

   strFormat := `Cannot proceed, the divider is zero.

dividee: %d 

divider: 0`

   return errors.New(fmt.Sprintf(strFormat, err.dividee))

}

//定义除法运算

func divide(vardividee int, vardivider int)(result int, errmsg error){

   if vardivider == 0{

      divideErr := DivideError{

         dividee:vardividee,

         divider:vardivider,

      }

      errmsg = divideErr.Error()

      return 0,errmsg

   }else{

      return vardividee/vardivider,nil

   }

}

func main() {

   //正常情况

   if result, err := divide(100, 10); err != nil{

      fmt.Println(err)

   }else{

      fmt.Println("100/10 = ", result)

   }

   //当被除数为零的时候会返回错误信息

   if _, errorMsg := divide(100, 0); errorMsg != nil{

      fmt.Println(errorMsg)

   }

}

三、异常处理

1、异常处理简介

Go使用panic()函数抛出异常,在defer语句中调用recover()函数捕获异常。

func panic(interface{})//接受任意类型参数 无返回值 

func recover() interface{}//可以返回任意类型 无参数

panic()是一个内置函数,可以中断原有的控制流程,进入一个panic流程中。当函数F调用panic,函数F的执行被中断,但F中的延迟函数(必须是在panic前的已加载的defer)会正常执行,然后F函数逐层向上返回,直到发生panic的goroutine中所有调用的函数返回,此时程序退出。异常可以直接调用panic产生,也可以由运行时错误产生,例如访问越界的数组。

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

一般情况下,recover()应该在一个使用defer关键字的函数中执行以有效截取错误处理流程。如果没有在发生异常的goroutine中明确调用恢复过程(使用recover关键字),会导致goroutine所属的进程打印异常信息后直接退出。

2、异常处理使用示例

package main

import (

   "errors"

   "fmt"

)

//定义一个DivideError类型

type DivideError struct {

   dividee int

   divider int

}

//实现error接口

func (err *DivideError) Error() error{

   strFormat := `Cannot proceed, the divider is zero.

dividee: %d 

divider: 0`

   return errors.New(fmt.Sprintf(strFormat, err.dividee))

}

//定义除法运算

func divide(dividee int, divider int)(result int){

   defer func() {

      if r := recover();r != nil{

         divideErr := DivideError{

            dividee:dividee,

            divider:divider,

         }

         fmt.Println(divideErr.Error())

      }

   }()

   result = dividee/divider

   return result

}

func main() {

   a := divide(100,0)

   fmt.Println(a)

}

©著作权归作者所有:来自51CTO博客作者天山老妖S的原创作品,如需转载,请注明出处,否则将追究法律责任


打开App,阅读手记
0人推荐
发表评论
随时随地看视频慕课网APP