实验深度理解Go中try...catch...的panic、defer、recover用法

简介: 文章通过实验代码演示了Go语言中如何使用panic、defer和recover函数来模拟try...catch...的异常处理机制,并详细解释了每个函数的作用和在异常处理中的使用场景。

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。

Go中如何写try...catch...

go中是没有try...catch...语法的,但是仍提供了实现类似功能的panic、defer、recover函数来实现try...catch...。那么具体该如何实现呢?我们就从一个小目标开启实验之旅。实验目标:异常时正确返回期望的结构体数据

panic、defer、recover实验

1. 设计实验代码

package main

import "fmt"

type TxInfo struct {
    ChainId   string `json:"chainId"`
    Hash      string `json:"hash"`
    BlockHash string `json:"blockHash"`
}

func main() {
    ti := TxInfo{
        ChainId: "1",
        Hash:    "0x86a5a6074cce7d1f418b41f363a22e64426dba10039f120832af064c8aa1266f",
    }
    ri := &TxInfo{
        ChainId: "1",
        Hash:    "0x86a5a6074cce7d1f418b41f363a22e64426dba10039f120832af064c8aa1266f",
    }
    fmt.Println("Test1 Start:=======================")
    ni := parserValue(ti)
    fmt.Println("ni", ni)
    fmt.Println("ti", ti)

    fmt.Println("Test2 Start:=======================")
    nj := parserValue1(ti)
    fmt.Println("nj", nj)
    fmt.Println("ti", ti)

    fmt.Println("Test3 Start:=======================")
    ti = normalValue(ti)
    fmt.Println("ti", ti)

    fmt.Println("Test4 Start:=======================")
    parserReference(ri)
    fmt.Println("ri", *ri)
}

func normalValue(ti TxInfo) TxInfo {

    //保留的还是初识栈的值
    defer handleExceptionValue(ti)

    ti.BlockHash = "14972319"

    //说明了这不是一个原子操作,进行了成功赋值
    return ti

}

func parserValue(ti TxInfo) TxInfo {

    //保留的还是初识栈的值
    defer handleExceptionValue(ti)

    ti.BlockHash = "14972317"

    //尽管handleExcpetionValue中有return 副本的变量,但是parserValue并没有通过return进行赋值返回,所以parserValue返回ni {  }
    panic("parserValue error")

}

//通过指定返回变量t的方式,就不需要在用return了,因为已经包含了赋值+return功能了
func parserValue1(ti TxInfo) (t TxInfo) {

    //保留的还是初识栈的值
    defer handleExceptionValue(ti) //如果这里是ti的话,handleExceptionValue打印的是当前对象{1 0x86a5a6074cce7d1f418b41f363a22e64426dba10039f120832af064c8aa1266f }
    //defer handleExceptionValue(t) //如果这里是t的话,目前t还是空对象,所以handleExceptionValue打印的是{}
    //defer handleExceptionNoRecover(ti) //因为里面不包含recover()函数,所以整个服务就停止运行;和没有defer的效果是一样的

    //改为变量赋值的方式来返回
    t = ti
    t.BlockHash = "14972311"

    fmt.Println("Inner ti:", ti) // {1 0x86a5a6074cce7d1f418b41f363a22e64426dba10039f120832af064c8aa1266f } 说明是值传递,即t的改变并未改变ti
    fmt.Println("Inner t:", t)   //{1 0x86a5a6074cce7d1f418b41f363a22e64426dba10039f120832af064c8aa1266f 14972311}

    panic("parserValue1 error")

}

//对于引用,无需返回,不惧怕中间繁盛Panic导致的还未赋值,推荐的做法
func parserReference(ri *TxInfo) {

    defer handleExceptionReference("parserReference")

    ri.BlockHash = "14972318"

    panic("parserReference error")

}

func handleExceptionNoRecover(ti TxInfo) TxInfo {
    fmt.Println(ti, "handleExceptionNoRecover-Recover:", ti)
    return ti
}

func handleExceptionValue(ti TxInfo) TxInfo {
    if r := recover(); r != nil {
        fmt.Println(ti, "handleExceptionValue-Recover:", r)
    }
    return ti
}

func handleExceptionReference(funcname string) {
    if r := recover(); r != nil {
        fmt.Println(funcname, "handleExceptionReference-Recover:", r)
    }
}

2. 实验代码运行输出

Test1 Start:=======================
{
   1 0x86a5a6074cce7d1f418b41f363a22e64426dba10039f120832af064c8aa1266f } handleExceptionValue-Recover: parserValue error
ni {
     }
ti {
   1 0x86a5a6074cce7d1f418b41f363a22e64426dba10039f120832af064c8aa1266f }
Test2 Start:=======================
Inner ti: {
   1 0x86a5a6074cce7d1f418b41f363a22e64426dba10039f120832af064c8aa1266f }
Inner t: {
   1 0x86a5a6074cce7d1f418b41f363a22e64426dba10039f120832af064c8aa1266f 14972311}
{
   1 0x86a5a6074cce7d1f418b41f363a22e64426dba10039f120832af064c8aa1266f } handleExceptionValue-Recover: parserValue1 error
nj {
   1 0x86a5a6074cce7d1f418b41f363a22e64426dba10039f120832af064c8aa1266f 14972311}
ti {
   1 0x86a5a6074cce7d1f418b41f363a22e64426dba10039f120832af064c8aa1266f }
Test3 Start:=======================
ti {
   1 0x86a5a6074cce7d1f418b41f363a22e64426dba10039f120832af064c8aa1266f 14972319}
Test4 Start:=======================
parserReference handleExceptionReference-Recover: parserReference error
ri {
   1 0x86a5a6074cce7d1f418b41f363a22e64426dba10039f120832af064c8aa1266f 14972318}

3. 基于实验进行原理讲解

参考

相关文章
|
6月前
|
JSON 人工智能 Go
go 反射的常见用法
go 反射的常见用法
57 4
|
6月前
|
人工智能 编译器 Go
go slice 基本用法
go slice 基本用法
70 1
|
6月前
|
存储 Go
掌握 Go 语言的 defer 关键字
掌握 Go 语言的 defer 关键字
|
6月前
|
Go 调度 C语言
go语言中一些用法
本文详细解析了Go语言如何通过C语言扩展其功能。主要包括:使用注释书写C代码、通过Go调用C中的函数示例及背后的工作原理;解释了Go如何通过内存结构体传递参数并接收返回值,以及Go调度器如何处理C代码执行期间的控制流问题;讨论了使用cgo的优势与局限性;最后介绍了Go语言中`defer`关键字的工作机制,并通过具体示例展示了反射在动态调用函数中的应用。
|
8月前
|
Unix Shell 编译器
Go 中空结构有什么用法
在 Go 语言中,空结构体 struct{} 是一个非常特殊的类型,它不包含任何字段并且不占用任何内存空间。虽然听起来似乎没什么用,但空结构体在 Go 编程中实际上有着广泛的应用。本文将详细探讨空结构体的几种典型用法,并解释为何它们在特定场景下非常有用。
|
9月前
|
Java Go 区块链
【Go语言专栏】Go语言中的延迟执行与defer语句
【4月更文挑战第30天】Go语言的延迟执行与defer语句用于资源释放和错误处理。defer通过关键字定义,函数返回时执行,顺序与定义相反。参数在定义时求值。应用包括资源释放、错误处理、成对操作和函数包装,是Go编程的关键特性。
72 0
|
2月前
|
存储 监控 算法
员工上网行为监控中的Go语言算法:布隆过滤器的应用
在信息化高速发展的时代,企业上网行为监管至关重要。布隆过滤器作为一种高效、节省空间的概率性数据结构,适用于大规模URL查询与匹配,是实现精准上网行为管理的理想选择。本文探讨了布隆过滤器的原理及其优缺点,并展示了如何使用Go语言实现该算法,以提升企业网络管理效率和安全性。尽管存在误报等局限性,但合理配置下,布隆过滤器为企业提供了经济有效的解决方案。
95 8
员工上网行为监控中的Go语言算法:布隆过滤器的应用
|
4天前
|
监控 Linux PHP
【02】客户端服务端C语言-go语言-web端PHP语言整合内容发布-优雅草网络设备监控系统-2月12日优雅草简化Centos stream8安装zabbix7教程-本搭建教程非docker搭建教程-优雅草solution
【02】客户端服务端C语言-go语言-web端PHP语言整合内容发布-优雅草网络设备监控系统-2月12日优雅草简化Centos stream8安装zabbix7教程-本搭建教程非docker搭建教程-优雅草solution
51 20
|
2天前
|
存储 监控 算法
探秘员工泄密行为防线:基于Go语言的布隆过滤器算法解析
在信息爆炸时代,员工泄密行为对企业构成重大威胁。本文聚焦布隆过滤器(Bloom Filter)这一高效数据结构,结合Go语言实现算法,帮助企业识别和预防泄密风险。通过构建正常操作“指纹库”,实时监测员工操作,快速筛查可疑行为。示例代码展示了如何利用布隆过滤器检测异常操作,并提出优化建议,如调整参数、结合日志分析系统等,全方位筑牢企业信息安全防线,守护核心竞争力。
|
10天前
|
Go C语言
Go语言入门:分支结构
本文介绍了Go语言中的条件语句,包括`if...else`、`if...else if`和`switch`结构,并通过多个练习详细解释了它们的用法。`if...else`用于简单的条件判断;`if...else if`处理多条件分支;`switch`则适用于基于不同值的选择逻辑。特别地,文章还介绍了`fallthrough`关键字,用于优化重复代码。通过实例如判断年龄、奇偶数、公交乘车及成绩等级等,帮助读者更好地理解和应用这些结构。
34 14

热门文章

最新文章