我的编程空间,编程开发者的网络收藏夹
学习永远不晚

Golang异常处理之defer,panic,recover的使用详解

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

Golang异常处理之defer,panic,recover的使用详解

延迟是什么

defer即延迟语句,极个别的情况下,Go才使⽤defer、panic、recover这种异常处理形式。

defer可以延迟函数、延迟⽅法、延迟参数。

延迟函数

可以在函数中添加多个defer语句。

当函数执⾏到最后时,这些defer语句会按照逆序执⾏,最后该函数返回。特别是当你在进⾏⼀些打开资源的操作时,遇到错误需要提前返回,在返回前你需要关闭

相应的资源,不然很容易造成资源泄露等问题

如果有很多调⽤defer,那么defer是采⽤后进先出模式

在离开所在的⽅法时,执⾏(报错的时候也会执⾏)

示例代码1:

package main
import "fmt"
func main() {
 defer funA()
 funB()
 funC()
 fmt.Println("main...over....") }
func funA() {
 fmt.Println("我是funA()...") }
func funB() { //
 fmt.Println("我是funB()...") }
func funC() {
 fmt.Println("我是funC()。。") }

运⾏结果:

我是funB()...
我是funC()。。
main...over....
我是funA()...

示例代码2:

package main
import "fmt"
func main() {
 s1 := []int{78, 109, 2, 563, 300}
 largest(s1) }
func finished() {
 fmt.Println("结束!") }
func largest(s []int) {
 defer finished()
 fmt.Println("开始寻找最⼤数...")
 max := s[0]
 for _, v := range s {
 if v > max {
 max = v
 }
 }
 fmt.Printf("%v中的最⼤数为:%v \n", s , max) }

运⾏结果:

开始寻找最⼤数…
[78 109 2 563 300]中的最⼤数为:563
结束!

延迟⽅法

延迟并不仅仅局限于函数。延迟⼀个⽅法调⽤也是完全合法的。

示例代码:

package main
import "fmt"
type person struct {
 firstName string
 lastName string
}
func (p person) fullName() {
 fmt.Printf("%s %s", p.firstName, p.lastName) }
func main() {
 p := person{"Steven", "Wang"}
 defer p.fullName()
 fmt.Printf("Welcome ") }

运⾏结果:

Welcome Steven Wang

延迟参数

延迟函数的参数在执⾏延迟语句时被执⾏,⽽不是在执⾏实际的函数调⽤时执⾏。

示例代码:

package main
import "fmt"
func printAdd(a , b int) {
 fmt.Printf("延迟函数中:参数a , b分别为%d,%d ,两数之和为:%d\n",
a , b , a+b) }
func main() {
 a := 5
 b := 6
 //延迟函数的参数在执⾏延迟语句时被执⾏,⽽不是在执⾏实际的函数调
⽤时执⾏。
 defer printAdd(a , b)
 a = 10
 b = 7
 fmt.Printf("延迟函数执⾏前:参数a , b分别为%d,%d ,两数之和为:
%d\n", a , b , a+b) }

运⾏结果:

延迟函数执⾏前:参数a , b分别为10,7 ,两数之和为:17
延迟函数中:参数a , b分别为5,6 ,两数之和为:11

堆栈的推迟

当⼀个函数有多个延迟调⽤时,它们被添加到⼀个堆栈中,并在Last In First Out(LIFO)后进先出的顺序中执⾏。

示例代码:利⽤defer实现字符串倒序

package main
import "fmt"
func main() {
 name := "StevenWang欢迎学习区块链"
 fmt.Printf("原始字符串: %s\n", name)
 fmt.Println("翻转后字符串: ")
 ReverseString(name) }
func ReverseString(str string) {
 for _, v := range []rune(str) {
 defer fmt.Printf("%c", v)
 }
}

返回结果:

原始字符串: StevenWang欢迎学习区块链
翻转后字符串:
链块区习学迎欢gnaWnevetS

延迟的应⽤

到⽬前为⽌,我们所写的示例代码,并没有实际的应⽤。现在看⼀下关于延迟的应⽤。在不考虑代码流的情况下,延迟被执⾏。让我们以⼀个使⽤WaitGroup的程序示例来理解这个问题。我们将⾸先编写程序⽽不使⽤延迟,然后我们将修改它以使⽤延迟,并理解延迟是多么有⽤。

示例代码:

package main
import (
 "fmt"
 "sync"
)
type rect struct {
 length int
 width int
}
func (r rect) area(wg *sync.WaitGroup) {
 if r.length < 0 {
 fmt.Printf("rect %v's length should be greater than zero\n", r)
 wg.Done()
 return
 }
 if r.width < 0 {
 fmt.Printf("rect %v's width should be greater than zero\n", r)
 wg.Done()
 return
 }
 area := r.length * r.width
 fmt.Printf("rect %v's area %d\n", r, area)
 wg.Done()
}
func main() {
 var wg sync.WaitGroup
 r1 := rect{-67, 89}
 r2 := rect{5, -67}
 r3 := rect{8, 9}
 rects := []rect{r1, r2, r3}
 for _, v := range rects {
 wg.Add(1)
 go v.area(&wg)
 }
 wg.Wait()
 fmt.Println("All go routines finished executing")
}

修改以上代码:

package main
import (
 "fmt"
 "sync"
)
type rect struct {
 length int
 width int
}
func (r rect) area(wg *sync.WaitGroup) {
 defer wg.Done()
 if r.length < 0 {
 fmt.Printf("rect %v's length should be greater than zero\n", r)
 return
 }
 if r.width < 0 {
 fmt.Printf("rect %v's width should be greater than zero\n", r)
 return
 }
 area := r.length * r.width
 fmt.Printf("rect %v's area %d\n", r, area) }
func main() {
 var wg sync.WaitGroup
 r1 := rect{-67, 89}
 r2 := rect{5, -67}
 r3 := rect{8, 9}
 rects := []rect{r1, r2, r3}
 for _, v := range rects {
 wg.Add(1)
 go v.area(&wg)
 }
 wg.Wait()
 fmt.Println("All go routines finished executing")
}

程序运⾏结果:

rect {8 9}'s area 72
rect {-67 89}'s length should be greater than zero
rect {5 -67}'s width should be greater than zero
All go routines finished executing

panic和recover(宕机和宕机恢复)

panic和recover机制

1.概述:

panic:词义"恐慌",recover:“恢复”

Go语⾔追求简洁优雅,Go没有像Java那样的 try…catch…finally 异常处理机制。Go语⾔设计者认为,将异常与流程控制混在⼀起会让代码变得混乱。

Go语⾔中,使⽤多值返回来返回错误。不⽤异常代替错误,更不⽤异常来控制流程。

go语⾔利⽤panic(),recover(),实现程序中的极特殊的异常处理。换句话说,极个别的情况下,Go才使⽤defer、panic、recover这种异常处理形式。

  • panic(),让当前的程序进⼊恐慌,中断程序的执⾏。或者说,panic是⼀个内建函数,可以中断原有的控制流程,进⼊⼀个令⼈恐慌的流程中。
  • 当函数F调⽤panic,函数F的执⾏被中断,但是F中的延迟函数会正常执⾏,然后F返回到调⽤它的地⽅。在调⽤的地⽅,F的⾏为就像调⽤了panic。这⼀过程继续向上,直到发⽣panic的goroutine中所有调⽤的函数返回,此时程序退出。
  • 恐慌可以直接调⽤panic产⽣。也可以由运⾏时错误产⽣,例如访问越界的数组。
  • recover 是⼀个内建的函数,可以让进⼊令⼈恐慌的流程中的goroutine恢复过来。
  • recover(),让程序恢复,必须在defer函数中执⾏。换句话说,recover仅在延迟函数中有效。
  • 在正常 的执⾏过程中,调⽤recover会返回nil,并且没有其它任何效果。如果当前的goroutine陷⼊恐慌,调⽤ recover可以捕获到panic的输⼊值,并且恢复正常的执⾏。

⼀定要记住,应当把它作为最后的⼿段来使⽤,也就是说,我们的代码中应当没有,或者很少有panic这样的东⻄。

示例代码

package main
import "fmt"
func main() {
 
 funA()
 funB()
 funC()
 fmt.Println("main...over....") }
func funA() {
 fmt.Println("我是函数funA()...") }
func funB() { //外围函数
 defer func() {
 if msg := recover(); msg != nil {
 fmt.Println(msg, "恢复啦。。。")
 }
 }()
 fmt.Println("我是函数funB()...")
 for i := 1; i <= 10; i++ {
 fmt.Println("i:", i)
 if i == 5 {
 //让程序中断
 panic("funB函数,恐慌啦。。。") //打断程序的执⾏。。
 }
 }
 //当外围函数中的代码引发运⾏恐慌时,只有其中所有的延迟函数都执⾏完毕后,该运
⾏时恐慌才会真正被扩展⾄调⽤函数。
}
func funC() {
 defer func() {
 fmt.Println("func的延迟函数。。。")
 //if msg := recover(); msg != nil {
 // fmt.Println(msg, "恢复啦。。。")
 //}
 fmt.Println("recover执⾏了" , recover())
 }()
 fmt.Println("我是函数funC()。。")
 panic("funC恐慌啦。。") }

以上就是Golang异常处理之defer,panic,recover的使用详解的详细内容,更多关于Golang defer panic recover的资料请关注编程网其它相关文章!

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

Golang异常处理之defer,panic,recover的使用详解

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

Golang异常处理之defer,panic,recover如何使用

今天小编给大家分享一下Golang异常处理之defer,panic,recover如何使用的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来
2023-06-30

Golang异常处理中的panic和recover

在 go 中,panic 和 recover 用于异常处理。panic 用来报告异常,recover 用来从异常中恢复。panic 会停止程序执行,抛出一个 interface{} 类型的异常值。recover 可以从延迟函数或 gorou
Golang异常处理中的panic和recover
2024-04-15

Go错误处理之panic函数和recover函数使用及捕获异常方法

这篇文章主要介绍了Go错误处理之panic函数使用及捕获,本篇探讨了如何使用panic和recover来处理Go语言中的异常,需要的朋友可以参考下
2023-03-24

Golang中的panic之避免和处理程序中的异常情况

Golang中的panic是一种异常处理机制,可以在程序出现异常情况时终止程序并打印错误信息。为了避免panic对程序的影响,开发者可以采用一系列技巧,如defer+recover、编写可重入的代码、使用错误返回值等。这些技巧可以帮助开发者优雅地处理程序中的异常情况
2023-05-16

Go之panic函数和recover函数使用及捕获异常的方法是什么

这篇文章主要介绍“Go之panic函数和recover函数使用及捕获异常的方法是什么”,在日常操作中,相信很多人在Go之panic函数和recover函数使用及捕获异常的方法是什么问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法
2023-07-05

详解Java异常处理的使用与思考

异常处理的概念起源于早期的编程语言,如 LISP、PL/I 和 CLU。这些编程语言首次引入了异常处理机制,以便在程序执行过程中检测和处理错误情况。本文主要来介绍一下Java中的异常处理,需要的可以参考一下
2023-05-15

C++异常处理noexcept正确使用示例详解

这篇文章主要为大家介绍了C++异常处理noexcept正确使用示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
2023-05-17

Java异常处理UncaughtExceptionHandler使用实例代码详解

当一个线程由于未捕获异常即将终止时,Java虚拟机将使用thread.getuncaughtexceptionhandler()查询线程的uncaughtException处理程序,并调用处理程序的uncaughtException方法,将线程和异常作为参数传递
2023-03-01

在SQL Server中使用 Try Catch 处理异常的示例详解

目录如何在 SQL Server 中使用 Try Catch 处理错误?示例:了解 SQL Server 中的 Try-Catch 实现。在 SQL Server 中使用 try-catch 的示例如何在 SQL Server 中使用 Tr
2022-07-14

详解如何在SpringBoot项目中使用全局异常处理

在完整的项目开发中,异常的出现几乎是无法避免的;如果凡是有可能出现异常的地方,我们都手动的使用try-catch将其捕获的话,会使得代码显得十分臃肿并且后期不好维护。本文介绍了pringBoot项目中使用全局异常处理的方法,需要的可以参考一下
2022-11-13

C++ 技术中的异常处理:如何使用异常对象来获取异常详细信息?

c++++ 异常处理获取异常详细信息的方法:使用异常对象 e.name() 获取异常类型。使用 e.what() 获取描述异常原因的文本消息。C++ 中的异常处理:揭秘获取异常详细信息的异常对象异常处理在 C++ 中扮演着至关重要的角色,
C++ 技术中的异常处理:如何使用异常对象来获取异常详细信息?
2024-05-10

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录