温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

如何用Go语言异常机制模拟TryCatch异常捕捉

发布时间:2021-10-11 09:53:18 来源:亿速云 阅读:136 作者:iii 栏目:编程语言

这篇文章主要讲解了“如何用Go语言异常机制模拟TryCatch异常捕捉”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“如何用Go语言异常机制模拟TryCatch异常捕捉”吧!

  不管是什么异常处理机制,核心的原理都是一样的,通常来讲,一个完善的异常处理机制需要由下面3部分组成。

  抛出异常

  处理异常的代码段

  获取异常信息

  下面先用Java的异常处理机制来说明这一点。

  import java.io.IOException;

  public class Main {

  public static void main(String[] args) {

  try

  {

  boolean ioException = false;

  if (ioException) {

  throw new IOException("ioexception");

  } else {

  throw new Exception("exception");

  }

  }

  catch (IOException e) {

  System.err.println(e);

  }

  catch (Exception e) {

  System.out.println(e);

  }

  finally

  {

  System.out.println("finally");

  }

  }

  }

  上面的代码是标准的Java异常处理机制,try部分的throw用于抛出异常,而catch部分的代码段用于处理特定的异常,通过catch子句的参数e可以获取异常信息。所以对于Java来说,上述的3个异常重要的组成部分都有。

  对于Go语言来说,panic、defer和recover也分别对应了这3部分。其中panic是一个函数,用于抛出异常,相当于Java中的throw函数。defer是一个关键字,用于修饰函数,用defer修饰的函数,在抛出异常时会自动调用。recover是一个函数,用于获取异常信息,通常在用defer修饰的函数中使用。

  下面是一段用Go语言处理异常的代码。

  package main

  import "fmt"

  func main(){

  //  处理异常的函数

  defer func(){

  fmt.Println("开始处理异常")

  // 获取异常信息

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

  //  输出异常信息

  fmt.Println("error:",err)

  }

  fmt.Println("结束异常处理")

  }()

  exceptionFun()

  }

  func exceptionFun(){

  fmt.Println("exceptionFun开始执行")

  panic("异常信息")

  fmt.Println("exceptionFun执行结束")

  }

  实现Go版的TryCatch

  现在已经了解了Go语言的异常处理机制,那么接下来使用异常处理机制来模拟try...catch...finally语句。

  现在来分析一下如果模拟。模拟的过程需要完成下面的工作。

  try、catch和finally这3部分都有各自的代码段,所以为了模拟try...catch...finally,需要用3个Go函数来分别模拟try、catch和finally部分的代码段。这3个Go函数是Try、Catch和Finally。

  要确定这3个函数在什么地方调用。Try是正常执行的代码,所以在要首先调用Try函数。而Catch函数只有在抛出异常时调用,所以应该在用defer修饰的函数中调用,而且需要在Catch函数中获取异常信息,所以应该在使用cover函数获取异常信息后再调用Catch函数,通常会将异常信息直接作为参数传递给Catch函数。不管是否抛出异常,Finally函数都必须调用,所以应该用defer修饰Finally函数,而且是第1个用defer修饰的函数。这样,在当前函数结束之前一定刚回调用Finally函数。

  触发异常,这就非常简单了,直接用panic函数即可。

  上面清楚地描述了用Go语言的异常处理机制模拟try...catch...finally语句的基本原理,下面给出完整的实现代码。

  package main

  import (

  "fmt"

  )

  type ExceptionStruct struct {

  Try     func()

  Catch   func(Exception)

  Finally func()

  }

  type Exception interface{}

  func Throw(up Exception) {

  panic(up)

  }

  func (this ExceptionStruct) Do() {

  if this.Finally != nil {

  defer this.Finally()

  }

  if this.Catch != nil {

  defer func() {

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

  this.Catch(e)

  }

  }()

  }

  this.Try()

  }

  func main() {

  fmt.Println("开始执行...")

  ExceptionStruct{

  Try: func() {

  fmt.Println("try...")

  Throw("发生了错误")

  },

  Catch: func(e Exception) {

  fmt.Printf("exception %v\n", e)

  },

  Finally: func() {

  fmt.Println("Finally...")

  },

  }.Do()

  fmt.Println("结束运行")

  }

  上面的代码将Try、Catch、Finally函数都封装在了ExceptionStruct结构体中。然后调用方式就与前面的描述的一致了。执行这段代码,会输出如下图的信息。

  image.png

  增强版的TryCatch

  到现在为止,其实已经完整地实现了try...catch...finally语句,但细心的同学会发现,这个实现有一点小问题。通常的try...catch...finally语句,try部分有且只有1个,finally部分是可选的,但最多只能有1个,而catch部分也是可选的,可以有0到n个,也就是catch部分可以有任意多个。但前面的实现,Catch函数只能指定一个,如果要指定任意多个应该如何做呢?其实很简单,用一个Catch函数集合保存所有指定的Catch函数即可。不过需要快速定位某一个Catch函数。在Java中,是通过异常类型(如IOException、Exception等)定位特定的catch子句的,我们也可以模拟这一过程,通过特定的异常来定位与该异常对应的Catch函数,为了方便,可以用int类型的异常代码。那么在调用Catch函数之前,就需要通过异常代码先定位到某一个Catch函数,然后再调用。下面就是完整的实现代码。

  package main

  import (

  "log"

  )

  type Exception struct {

  Id int       // exception id

  Msg string   // exception msg

  }

  type TryStruct struct {

  catches map[int]ExceptionHandler

  try   func()

  }

  func Try(tryHandler func()) *TryStruct {

  tryStruct := TryStruct{

  catches: make(map[int]ExceptionHandler),

  try: tryHandler,

  }

  return &tryStruct

  }

  type ExceptionHandler func(Exception)

  func (this *TryStruct) Catch(exceptionId int, catch func(Exception)) *TryStruct {

  this.catches[exceptionId] = catch

  return this

  }

  func (this *TryStruct) Finally(finally func()) {

  defer func() {

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

  exception := e.(Exception)

  if catch, ok := this.catches[exception.Id]; ok {

  catch(exception)

  }

  finally()

  }

  }()

  this.try()

  }

  func Throw(id int, msg string) Exception {

  panic(Exception{id,msg})

  }

  func main() {

  exception.Try(func() {

  log.Println("try...")

  //  指定了异常代码为2,错误信息为error2

  exception.Throw(2,"error2")

  }).Catch(1, func(e exception.Exception) {

  log.Println(e.Id,e.Msg)

  }).Catch(2, func(e exception.Exception) {

  log.Println(e.Id,e.Msg)

  }).Finally(func() {

  log.Println("finally")

  })

  }

  执行结果如下图所示。

  image.png

  这个实现与Java中的try...catch...finally的唯一区别就是必须要调用Finally函数,因为处理异常的代码都在Finally函数中。不过这并不影响使用,如果finally部分没什么需要处理的,那么就设置一个空函数即可。

  为了方便大家,我已经将该实现封装成了函数库,调用代码如下:

  package main

  import (

  "exception"

  "log"

  )

  func main() {

  exception.Try(func() {

  log.Println("try...")

  exception.Throw(2,"error2")

  }).Catch(1, func(e exception.Exception) {

  log.Println(e.Id,e.Msg)

  }).Catch(2, func(e exception.Exception) {

  log.Println(e.Id,e.Msg)

  }).Finally(func() {

  log.Println("finally")

  })

  }

感谢各位的阅读,以上就是“如何用Go语言异常机制模拟TryCatch异常捕捉”的内容了,经过本文的学习后,相信大家对如何用Go语言异常机制模拟TryCatch异常捕捉这一问题有了更深刻的体会,具体使用情况还需要大家实践验证。这里是亿速云,小编将为大家推送更多相关知识点的文章,欢迎关注!

向AI问一下细节

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

AI