Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >你听说过Go语言的TryCatch吗?

你听说过Go语言的TryCatch吗?

作者头像
蒙娜丽宁
发布于 2020-04-14 08:02:23
发布于 2020-04-14 08:02:23
1.3K00
代码可运行
举报
文章被收录于专栏:极客起源极客起源
运行总次数:0
代码可运行

有的同学看到Go和TryCatch一起出现,心里可能会说,难道Go语言升级了,加入了try...catch语句。哈哈,其实Go语言从创建之初就没打算加入try...catch语句,因为创建Go的那帮大爷认为try...catch挺烦人的,如果滥用,会造成程序混乱,所以就不打算加入try...catch(以后加不加入不好说)。

既然Go语言中并没有try...catch语句,那么为何文章标题说要使用TryCatch呢?其实Go语言中只是没有try...catch语句,并不是没有异常处理机制。Go语言中的异常处理机制就是著名的异常三剑客:panic、defer和recover。通过这3个家伙,是完全可以模拟出try...catch语句效果的,对了,后面还应该有个finally。在正式模拟try...catch语句之前,先来回顾下Go语言中的异常处理机制是如何玩的。

1. Go语言中的异常处理机制

在前面提到,Go语言通过panic、defer和recover来处理异常的,那么这3个东西是什么呢?

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

  • 抛出异常
  • 处理异常的代码段
  • 获取异常信息

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

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
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语言处理异常的代码。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
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执行结束")
}

2. 实现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语句的基本原理,下面给出完整的实现代码。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
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结构体中。然后调用方式就与前面的描述的一致了。执行这段代码,会输出如下图的信息。

3. 增强版的TryCatch

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

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
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")
  })
}

执行结果如下图所示。

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

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

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
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")
  })
}
本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2019-11-24,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 极客起源 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
Go语言错误与异常处理机制
1 Error接口 Go语言中的error类型实际上是抽象了Error()方法的error接口
李海彬
2018/07/26
3940
Go语言错误与异常处理机制
Go语言错误处理
错误指的是可能出现问题的地方出现了问题,比如打开一个文件时可能失败,这种情况在人们的意料之中。
Steve Wang
2020/12/25
5260
Go语言入门——进阶语法篇(四)
Go语言没有类似Java或Python那种try...catch...机制处理异常,Go的哲学是与众不同的,Go的设计者认为主流的异常处理机制是一种被过度滥用的技巧,而且存在很大的潜在危害,Go的异常处理(或者说是错误处理)是一种非常简单直观的方式。通常的,我们在写Java、Python之类的代码时,遇到可能存在的异常,直接用try括起来,使用catch捕获,然后就万事大吉了,当系统长时间的运行时,大大增加了不稳定性,所积累的问题可能在某一刻爆发。而Go者使用一种称为"恐慌的"机制,在有必要时,直接让系统宕机,让问题发生时立刻暴露出来,不必累积。很难说哪种设计更好,但Go语言确实简化了代码。
arcticfox
2019/09/03
5370
Go 语言错误及异常处理篇(三):panic 和 recover
前面学院君介绍了 Go 语言通过 error 接口统一进行错误处理,但这些错误都是我们在编写代码时就已经预见并返回的,对于某些运行时错误,比如数组越界、除数为0、空指针引用,这些 Go 语言是怎么处理的呢?
学院君
2019/08/19
1.6K0
Go 语言错误及异常处理篇(三):panic 和 recover
golang错误处理笔记
Go语言中,错误被认为是一种可以预期的结果;而异常则是一种非预期的结果,发生异常可能表示程序中存在 BUG 或发生了其它不可控的问题。
lelezc
2022/12/01
5740
defer, panic和recover用法【Golang 入门系列十四】
以前讲过golang 的基本语法。但是,只是讲了一些基础的语法,感兴趣的可以看看以前的文章,https://www.cnblogs.com/zhangweizhong/category/1275863.html,前段时间有人问我defer,recover的用法。所以,还是统一的总结一下相关的关键字吧。
章为忠学架构
2019/09/25
2.2K0
<Go语言学习笔记>【异常处理】
通常 panic 和 recover 是用来处理异常问题的。我们来综述下,他们各自的特点:
Porco1Rosso
2020/11/19
1.6K0
<Go语言学习笔记>【异常处理】
Golang深入浅出之-Go语言 defer、panic、recover:异常处理机制
Go语言通过defer、panic和recover三个关键字构建了一种独特的异常处理机制。它们协同工作,使得Go程序能够优雅地处理运行时错误和异常情况。本文将深入浅出地解析这三个关键字的用法、特点以及常见问题与易错点,并通过代码示例进行演示。
Jimaks
2024/04/24
4.1K0
100天精通Golang(基础入门篇)——第23天:错误处理的艺术: Go语言实战指南
大家好,我是猫头虎!今天我们继续探索Go语言的奥秘,迎来了我们的第23天学习之旅。在这一天,我们将重点关注Go语言中的错误处理机制。在实际的工程项目中,通过程序错误信息快速定位问题是我们的期望,但我们又不希望错误处理代码显得冗余和啰嗦。Go语言通过函数返回值逐层向上抛出错误,与Java和C#的try...catch异常处理显著不同。这种设计理念鼓励工程师显式地检查错误,以避免忽略应处理的错误,从而确保代码的健壮性。🚀
猫头虎
2024/04/09
2180
100天精通Golang(基础入门篇)——第23天:错误处理的艺术: Go语言实战指南
【转】java中异常与try catch finally详解
程序运行时,发生的不被期望的事件,它阻止了程序按照程序员的预期正常执行,这就是异常。异常发生时,是任程序自生自灭,立刻退出终止,还是输出错误给用户?或者用C语言风格:用函数返回值作为执行状态?。
洋仔聊编程
2019/06/11
9070
牛客网_Go语言相关练习_判断&选择题(4)
错误指的是可能出现问题的地方出现了问题,比如打开一个文件时失败,这种情况在人们的意料之中;而异常指的是不应该出现问题的地方出现了问题,比如引用了空指针,这种情况在人们的意料之外。由此可知,错误是业务过程的一部分,而异常不是 。
Zoctopus
2018/08/10
8260
牛客网_Go语言相关练习_判断&选择题(4)
Go语言实战:错误处理和panic_recover之自定义错误类型
Go语言是一种现代的编程语言,它具有简洁的语法和强大的功能。在Go语言中,错误处理是一个重要的主题。Go语言提供了一种简洁的错误处理方式,即通过返回一个错误值来表示一个函数调用是否成功。此外,Go语言还提供了panic和recover机制,用于处理运行时错误。
阿珍
2025/02/22
1030
Go语言实战:错误处理和panic_recover之自定义错误类型
手把手教你用go语言实现异常处理
1. 错误处理:当函数返回一个错误值时,需要对该错误进行处理。可以使用`if err != nil`语句来检查错误,并采取相应的处理逻辑。
查拉图斯特拉说
2024/01/11
6090
手把手教你用go语言实现异常处理
Go语言入门——函数
使用struct去定义自己想要的数据模型就好比定义一个Java中的model一样……
JackieZheng
2019/07/02
4890
【初识Go】| Day10 异常处理
针对这样的情况,Go语言中引入 error 接口类型作为错误处理的标准模式,如果函数要返回错误,则返回值类型列表中肯定包含 error。error 处理过程类似于C语言中的错误码,可逐层返回,直到被处理。
yussuy
2020/12/23
2740
【初识Go】| Day10 异常处理
盘点Go语言中那些酷酷的语法
虽然写Go语言已经一年有余,认识Go语言已经近三年,但是写Go代码的快乐并未随着时间的推移而逐渐消沉,有时仍然会因为写一段伶俐的代码而感到很酷,所以想专门写一篇基础性的文章,来记录一下Go语言中那些很酷的语法,非常适合Go语言的新手同学哦!:laughing:
闫同学
2023/09/20
2460
Go语言原来还有王子救公主的故事?
刚接触 Golang 的同学,肯定会有一个疑惑就是,咋没有 try catch 这类的错误处理逻辑呀?
小锟哥哥
2022/05/10
2790
Go语言原来还有王子救公主的故事?
Go语言panic/recover的实现
本文主要分析Go语言的panic/recover在AMD64 Linux平台下的实现,包括:
阿波张
2019/07/04
1.3K0
golang当中的错误处理--筑基五层
在前面的几篇文章当中,我们主要是学习了Golang当中文件的读写以及数据的编码方式相关的知识。接下来,我们将开始来学习Golang中的错误处理。
闻说社
2025/05/13
970
golang当中的错误处理--筑基五层
Go语言基础速刷手册
这个“不务正业”的阿巩,今天冒着现学现卖的风险来和大家分享Go了,作为既具备C的理念又有Python 姿态的语言,怎么能不来试上一试呢!
才浅Coding攻略
2022/12/12
9170
相关推荐
Go语言错误与异常处理机制
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验