• 爱上开源之golang入门至实战第四章函数(Func)(十)


    爱上开源之golang入门至实战第四章函数(Func)(十)

    前言

    函数是各种编程语言里组成编程逻辑的主要部分;特别在Go语言中,Go语言削弱了面向对象编程的一些特性,比如构造函数,多态,抽象等,在函数式编程方面进行了类似于javascript和python等语言的借鉴,由此在咱们的第四章函数章节里,已经就细化了十个章节来进行各个方面的介绍。今天的这个文章,接着一文中对defer和recover的介绍,进一步深入的通过代码样例来学习函数。

     

    Recover的顺序

    我们把上一文中对processErrorPlus的调用代码,进行一下改造,把recover的processErrorPlus的defer调用,放在第二个defer之后,会有什么样的效果呢。

    调整后的代码

    1. func TestDeferFun8(t *testing.T) {
    2.   defer fmt.Println("Defer Func 1")
    3.   defer processErrorPlus(func(err error) {
    4.      fmt.Printf("Defer Func 2 error: %v\n", err)
    5.   })
    6.   defer fmt.Println("Defer Func 3")
    7.   fmt.Println("Test")
    8.   panic("This is a testing")
    9. }
    10. ===== OUTPUT =====
    11. Test
    12. Defer Func 3
    13. Defer Func 2 error: This is a testing
    14. Defer Func 1

    可以看到Recover在Defer Func 2中已经成功调用, 对后面的defer次序没有影响。

    Recover重复处理Error

    现在在每个defer都进行processErrorPlus调用, 并且修改processErrorPlus函数,函数processErrorPlus分别对recover存在error进行处理,和没有进行处理,修改后的processErrorPlus;如下代码

    1. type DoError func(err error)
    2. type DoNotError func()
    3. func processErrorPlus2(doError DoError, notError DoNotError) {
    4. if e := recover(); e != nil {
    5. if doError != nil {
    6. var err error
    7. switch x := e.(type) {
    8. case string:
    9. err = errors.New(x)
    10. case error:
    11. err = x
    12. default:
    13. err = errors.New("unknown panic")
    14. }
    15. doError(err)
    16. }
    17. } else {
    18. if notError != nil {
    19. notError()
    20. }
    21. }
    22. }

    如上代码,processErrorPlus2传入两个参数,都是函数类型的参数, 一个用来进行recover有error时的回调函数,一个用来进行recover没有error时的回调函数; 把主要的函数也进行修改, 三个defer函数都是用processErrorPlus2的函数处理;代码如下:

    1. func TestDeferFun9(t *testing.T) {
    2. defer processErrorPlus2(func(err error) {
    3. fmt.Printf("Defer Func 1 error: %v\n", err)
    4. }, func() {
    5. fmt.Printf("Defer Func 1 \n")
    6. })
    7. defer processErrorPlus2(func(err error) {
    8. fmt.Printf("Defer Func 2 error: %v\n", err)
    9. }, func() {
    10. fmt.Printf("Defer Func 2 \n")
    11. })
    12. defer processErrorPlus2(func(err error) {
    13. fmt.Printf("Defer Func 3 error: %v\n", err)
    14. }, func() {
    15. fmt.Printf("Defer Func 3 \n")
    16. })
    17. fmt.Println("Test")
    18. panic("This is a testing")
    19. }
    20. ===== OUTPUT =====
    21. Test
    22. Defer Func 3 error: This is a testing
    23. Defer Func 2
    24. Defer Func 1

    通过上面的代码样例,从执行结果来看, 当主函数里使用panic声明出异常;在依次执行三个defer函数中,

    先执行Defer Func 3这个processErrorPlus2的defer函数调用,在processErrorPlus2函数中,通过recover获取当前的error,此时error存在,故执行了传入的DoError的回调函数;也就输出了“Defer Func 3 error: This is a testing”;

    Func3段执行结束后,接下来执行Func2这段的processErrorPlus2的defer函数调用,此时再从recover中获取error,error已经在上个defer中获取完毕, 此时在获取error就为nil了;也就只会执行DoNotError的回调函数了。所以此时输出“Defer Func 2”;

    最后还有Func1的defer函数调用; 和第二个一样,前面的panic已经获取过了,这里recover的error亦然为nil;所以输出“Defer Func 1”;

    recover中的panic

    如果在回调里加入panic会是怎样了, 我们改下代码再来试试

    1. func TestDeferFun10(t *testing.T) {
    2. defer processErrorPlus2(func(err error) {
    3. fmt.Printf("Defer Func 1 error: %v\n", err)
    4. }, func() {
    5. fmt.Printf("Defer Func 1 \n")
    6. })
    7. defer processErrorPlus2(func(err error) {
    8. panic(fmt.Sprintf("Func 2 panic: %v", err))
    9. }, func() {
    10. fmt.Printf("Defer Func 2 \n")
    11. })
    12. defer processErrorPlus2(func(err error) {
    13. panic(fmt.Sprintf("Func 3 panic: %v", err))
    14. }, func() {
    15. fmt.Printf("Defer Func 3 \n")
    16. })
    17. fmt.Println("Test")
    18. panic("This is a testing")
    19. }
     
    

    这段代码对比上面的TestDeferFun9代码,我们来看看,在Func3和Func2的defer processErrorPlus2有些差别; Func3和Func2这里不是简单的打印出error了,而是把recover获取到的error包装成新的error,继续通过panic进行声明;这个操作类似于java中的,在try catch中获取到了exception后,再次通过throw进行exception的上抛。 结果会是如何,让我们来看看执行的结果:

    1. === RUN   TestDeferFun10
    2. Test
    3. Defer Func 1 error: Func 2 panic: Func 3 panic: This is a testing
    4. --- PASS: TestDeferFun10 (0.00s)
    5. PASS

    结束语

    通过这两遍介绍defer和recover的文章, 我们可以使用defer和recover的方式,完全的实现java里的exception处理的效果。

  • 相关阅读:
    ysoserial commonscollections6 分析
    calcite 初试-使用sql读取csv文件
    C++入门篇1
    实现表格表头自定义编辑、一键导入、增加列
    【编程题】【Scratch四级】2020.06 阶乘求和
    log4j2安全漏洞修复
    openssl3.2 - note - Writing OpenSSL Provider Skeleton
    DevEco Studio中如何设置HarmonyOS/OpenHarmony应用开发
    SpringBoot:SpringApplication.run的源码解析
    Jenkins一站成魔【2】传统项目CI/CD
  • 原文地址:https://blog.csdn.net/inthirties/article/details/126617478