Golang异常处理-panic与recover
Golang异常处理-panic与recover
作者:尹正杰
版权声明:原创作品,谢绝转载!否则将追究法律责任。
在程序设计中,容错是相当重要的一部分工作,在 Go中它是通过错误处理来实现的,error 虽然只是一个接口,但是其变化却可以有很多,我们可以根据自己的需求来实现不同的处理。任何时候当你需要一个新的错误类型,都可以用 errors (必须先 import)包的 errors.New 函数接收合适的错误信息来创建。
一.自定义的一个错误类型
/*
#!/usr/bin/env gorun
@author :yinzhengjie
Blog:http://www.cnblogs.com/yinzhengjie/tag/GO%E8%AF%AD%E8%A8%80%E7%9A%84%E8%BF%9B%E9%98%B6%E4%B9%8B%E8%B7%AF/
EMAIL:y1053419035@qq.com
*/ package main import (
"errors"
"fmt"
) var (
CustomError error //用于定义错误的变量。
PromptInformation string //用于定义提示信息的变量。
) func main() {
PromptInformation = "这是自定义的一个错误类型!"
CustomError = errors.New(PromptInformation) //errors包的New方法就可以创建一个error类型的数据,不过他需要你传入一个字符串类型用于给用户的提示信息。
fmt.Printf("error: %v", CustomError)
} #以上代码执行结果如下:
error: 这是自定义的一个错误类型!
二.调用自定义的错误
/*
#!/usr/bin/env gorun
@author :yinzhengjie
Blog:http://www.cnblogs.com/yinzhengjie/tag/GO%E8%AF%AD%E8%A8%80%E7%9A%84%E8%BF%9B%E9%98%B6%E4%B9%8B%E8%B7%AF/
EMAIL:y1053419035@qq.com
*/ package main import (
"errors"
"fmt"
) type Customer struct {
Name string
Deposit float64
} func CustomError()error { //这是我们自己定义的错误
return errors.New("对不起,您的余额已不足。")
} func TransferAccounts(name1, name2 Customer,money float64) (Customer,Customer,error) { //这个函数是用来实现转账的功能。
if name1.Deposit - money < 0 {
return name1,name2, CustomError()
}else {
name1.Deposit = name1.Deposit - money
name2.Deposit = name2.Deposit + money
}
return name1,name2, nil
} func main() {
yzj := Customer{"尹正杰",1000000}
Linus := Customer{"林纳斯·托瓦兹",100} name1,name2,err := TransferAccounts(yzj,Linus,50000) //如果在账户余额充足的情况下,是不会报错的,我们让他输入两个人各自的余额。
if err != nil {
fmt.Println(err)
}else {
fmt.Println(name1,name2)
} name1,name2,err = TransferAccounts(yzj,Linus,600000000000000) //注意,这是第二次调转账啦。这回我们故意把转账的金额写的远远大于存款。就会抛出我们定义的错误。
if err != nil {
fmt.Println(err)
}else {
fmt.Println(name1,name2)
}
} #以上代码执行结果如下:
{尹正杰 950000} {林纳斯·托瓦兹 50100}
对不起,您的余额已不足。
三.用 fmt 创建错误对象
/*
#!/usr/bin/env gorun
@author :yinzhengjie
Blog:http://www.cnblogs.com/yinzhengjie/tag/GO%E8%AF%AD%E8%A8%80%E7%9A%84%E8%BF%9B%E9%98%B6%E4%B9%8B%E8%B7%AF/
EMAIL:y1053419035@qq.com
*/ package main import (
"fmt"
) type Customer struct {
Name string
Deposit float64
} func TransferAccounts(name1, name2 Customer,money float64) (Customer,Customer,error) { //这个函数是用来实现转账的功能。
if name1.Deposit - money < 0 {
return name1,name2, fmt.Errorf("对不起,【%s】的用户余额已不足!",name1.Name) //通常你想要返回包含错误参数的更有信息量的字符串就可以用可以用 fmt.Errorf() 来实现。
}else {
name1.Deposit = name1.Deposit - money
name2.Deposit = name2.Deposit + money
}
return name1,name2, nil
} func main() {
yzj := Customer{"尹正杰",1000000}
Linus := Customer{"林纳斯·托瓦兹",100} name1,name2,err := TransferAccounts(yzj,Linus,50000) //如果在账户余额充足的情况下,是不会报错的,我们让他输入两个人各自的余额。
if err != nil {
fmt.Println(err)
}else {
fmt.Println(name1,name2)
} name1,name2,err = TransferAccounts(yzj,Linus,600000000000000) //注意,这是第二次调转账啦。这回我们故意把转账的金额写的远远大于存款。就会抛出我们定义的错误。
if err != nil {
fmt.Println(err)
}else {
fmt.Println(name1,name2)
}
} #以上代码执行结果如下:
{尹正杰 950000} {林纳斯·托瓦兹 50100}
对不起,【尹正杰】的用户余额已不足!
四.运行时异常和 panic
/*
#!/usr/bin/env gorun
@author :yinzhengjie
Blog:http://www.cnblogs.com/yinzhengjie/tag/GO%E8%AF%AD%E8%A8%80%E7%9A%84%E8%BF%9B%E9%98%B6%E4%B9%8B%E8%B7%AF/
EMAIL:y1053419035@qq.com
*/ package main import (
"bufio"
"os"
"fmt"
) var (
String string
Input string
) func main() {
f := bufio.NewReader(os.Stdin) //读取输入的内容
for {
fmt.Print("请输入您的用户名>")
Input,_ = f.ReadString('\n') //定义一行输入的内容分隔符。
if len(Input) == 1 {
continue //如果用户输入的是一个空行就让用户继续输入。
}
fmt.Printf("您输入的是:%s",Input)
fmt.Sscan(Input,&String)
if String == "stop" {
break
}
if String == "yinzhengjie" {
fmt.Println("欢迎登陆!")
}else {
panic("您输入的用户不存在!") //该程序要求用户输入一个字符串,一旦输入的字符串不是“yinzhengjie”就让程序直接崩溃掉。
}
}
} #以上代码执行结果如下:
请输入您的用户名>yinzhengjie
您输入的是:yinzhengjie
欢迎登陆!
请输入您的用户名>linus
您输入的是:linus
panic: 您输入的用户不存在! goroutine 1 [running]:
main.main()
E:/Code/Golang/Golang_Program/错误处理/4.运行时异常和 panic.go:38 +0x3b1 Process f
五.从 panic 中恢复(Recover)
/*
#!/usr/bin/env gorun
@author :yinzhengjie
Blog:http://www.cnblogs.com/yinzhengjie/tag/GO%E8%AF%AD%E8%A8%80%E7%9A%84%E8%BF%9B%E9%98%B6%E4%B9%8B%E8%B7%AF/
EMAIL:y1053419035@qq.com
*/ package main import (
"fmt"
) func badCall() { //定义一个让程序运行时崩溃的函数
panic("bad end")
} func test() {
defer func() {
if e := recover(); e != nil {
fmt.Printf("Panicing %s\n", e) //我们知道这个程序已经抛出了panic的错误了,但是我们用recover函数是可以处理这个错误的,我们这里的做法就是打印这个错误的输出并且不让程序崩溃。
}
}()
badCall() //调用这个运行时崩溃的函数,因此下面的一行代码是不会被执行的,而是直接结束当前函数,而结束函数之后就会触发defer关键字,因此会被recover函数捕捉。
fmt.Printf("After bad call\r\n") // <-- wordt niet bereikt
} func main() {
fmt.Printf("Calling test\r\n")
test() //调用我们定义的函数,发现程序并没有崩溃,而是可以继续执行下一行代码的哟!
fmt.Printf("Test completed\r\n")
} #以上代码执行结果如下:
Calling test
Panicing bad end
Test completed
六.自定义包中的错误处理和 panicking
/*
#!/usr/bin/env gorun
@author :yinzhengjie
Blog:http://www.cnblogs.com/yinzhengjie/tag/GO%E8%AF%AD%E8%A8%80%E7%9A%84%E8%BF%9B%E9%98%B6%E4%B9%8B%E8%B7%AF/
EMAIL:y1053419035@qq.com
*/ package main import (
"fmt"
"strings"
"strconv"
) type ParseError struct { //定义一个处理错误的结构体
key int
Value string
Err error
} func (p *ParseError) String() string { //给ParseError定义一个String()方法。
return fmt.Sprintf(" [%q] type is not int!" , p.Value)
} func JudgmentType(fields []string) (numbers []int) { //这个函数是判断fields切片中的每个元素是否都可以转换成INT类型的。
if len(fields) == 0 {
panic("Nothing can be explained!")
}
for key, value := range fields {
num, err := strconv.Atoi(value) //这里是讲每一个切片元素中的字符串进行转换。
if err != nil {
panic(&ParseError{key, value, err}) //如果解析出错就将自定义的ParseError结构体的error对象返回。
}
numbers = append(numbers, num) //如果转换成int类型没有出错的话就会被追加到一个提前定义好的切片中。
}
return //我们这里可以写numbers,说白了只要写一个[]int类型的都可以,当然,如果你不写的话默认就会返回我们提前定义好的numbers哟。
} func StringParse(input string) (numbers []int, err error) { //这个函数是用来解析字符串的。
defer func() { //用recover函数来接受panic抛出的错误信息。
if ErrorOutput := recover(); ErrorOutput != nil {
var ok bool
err, ok = ErrorOutput.(error) //很显然,这里是一种断言操作,即判断是否有error类型出现。
if !ok {
err = fmt.Errorf("Parse error: %v", ErrorOutput)
}
}
}()
fields := strings.Fields(input)
numbers = JudgmentType(fields)
return
} func main() {
var yzj = []string{
"100 200 300",
"1 2 2.5 3",
"30 * 40",
"yinzhengjie Golang",
"",
} for _, ex := range yzj {
fmt.Printf("正在解析[ %q]:\n ", ex)
result, err := StringParse(ex)
if err != nil {
fmt.Println("解析结果:",err)
continue
}
fmt.Println("解析结果:",result)
}
} #以上代码执行结果如下:
正在解析[ "100 200 300"]:
解析结果: [100 200 300]
正在解析[ "1 2 2.5 3"]:
解析结果: Parse error: ["2.5"] type is not int!
正在解析[ "30 * 40"]:
解析结果: Parse error: ["*"] type is not int!
正在解析[ "yinzhengjie Golang"]:
解析结果: Parse error: ["yinzhengjie"] type is not int!
正在解析[ ""]:
解析结果: Parse error: Nothing can be explained!
七.一种用闭包处理错误的模式
/*
#!/usr/bin/env gorun
@author :yinzhengjie
Blog:http://www.cnblogs.com/yinzhengjie/tag/GO%E8%AF%AD%E8%A8%80%E7%9A%84%E8%BF%9B%E9%98%B6%E4%B9%8B%E8%B7%AF/
EMAIL:y1053419035@qq.com
*/ package main import "fmt" func A() {
defer func() {
if r := recover(); r != nil {
fmt.Println("Recovered in A", r)
}
}()
fmt.Println("Calling A.")
B(0)
fmt.Println("Returned normally from g.")
} func B(i int) {
if i > 3 {
fmt.Println("Panicking!")
panic(fmt.Sprintf("%v", i))
}
defer fmt.Println("Defer in B", i)
fmt.Println("Printing in B", i)
B(i + 1) //这里是一个递归函数函数。
} func main() {
A()
fmt.Println("程序结束!")
} #以上地面执行结果如下:
Calling A.
Printing in B 0
Printing in B 1
Printing in B 2
Printing in B 3
Panicking!
Defer in B 3
Defer in B 2
Defer in B 1
Defer in B 0
Recovered in A 4
程序结束!
Golang异常处理-panic与recover的更多相关文章
- 【GoLang】panic defer recover 深入理解
唉,只能说C程序员可以接受go的错误设计,相比java来说这个设计真的很差劲! 我认为知乎上说的比较中肯的: 1. The key lesson, however, is that errors ar ...
- GO_05_2:Golang 中 panic、recover、defer 的用法
函数 defer 1. 它的执行方式类似其他语言中的折构函数,在函数体执行结束后按照调用顺序的 相反顺序 逐个执行 2. 即使函数发生 严重错误 也会被执行,类似于 java 中 try{...} ...
- Golang的panic和recover
panic 关键字panic的作用是制造一次宕机,宕机就代表程序运行终止,但是已经“生效”的延迟函数仍会执行(即已经压入栈的defer延迟函数,panic之前的). 为什么要制造宕机呢?是因为宕机不容 ...
- golang之panic,recover,defer
defer,recover: 运行时恐慌一旦被引发,就会向调用方传播直至程序崩溃. recover内建函数用于“拦截”运行时恐慌,可以使当前的程序从恐慌状态中恢复并重新获得流程控制权. recover ...
- GOLANG错误处理最佳方案errors wrap, Defer, Panic, and Recover
Simple error handling primitives: https://github.com/pkg/errors Defer, Panic, and Recover: ...
- Golang 高效实践之defer、panic、recover实践
前言 我们知道Golang处理异常是用error返回的方式,然后调用方根据error的值走不同的处理逻辑.但是,如果程序触发其他的严重异常,比如说数组越界,程序就要直接崩溃.Golang有没有一种异常 ...
- Golang错误处理函数defer、panic、recover、errors.New介绍
在默认情况下,当发生错误(panic)后,程序就会终止运行 如果发生错误后,可以捕获错误,并通知管理人员(邮件或者短信),程序还可以继续运行,这当然无可厚非 errors.New("错误信息 ...
- golang错误处理机制:panic与recover
原文地址:http://www.niu12.com/article/14 panic知识点 package main import ( "fmt" "github.com ...
- panic和recover的使用规则
转自个人博客 chinazt.cc 在上一节中,我们介绍了defer的使用. 这一节中,我们温习一下panic和recover的使用规则. 在golang当中不存在tye ... catch 异常处理 ...
随机推荐
- 蓝牙Remove Bond的流程分析
此篇文章简单分析一下蓝牙解除配对在协议栈中的工作流程.分析的协议栈版本是Android8.0 协议栈的接口都定义在bluetooth.cc这个文件中: static int remove_bond(c ...
- Zabbix实战-简易教程--大型分布式监控系统实现Agent批量快速接入
一.分布式架构 相信使用zabbix的大神都熟悉他的分布式架构,分布式的优势相当明显,分而治之.比如目前我的架构图如下: 那么,对将要接入监控系统的任何一个agent如何快速定位,并进行接入呢? 问 ...
- 设计模式 笔记 状态模式 State
//---------------------------15/04/28---------------------------- //State 状态模式----对象行为型模式 /* 1:意图: ...
- JS高级程序设计学习笔记1
javascript产生的原因: 在拨号上网时代,表单数据必须发送到服务器端才能验证输入值得有效性,JavaScript的研发就是为了解决这个问题,以便在客户端就验证输入值的有效性. ECMAScri ...
- 【Alpha阶段】M1事后报告
时间:2015-11-13 23:30 地点:七公寓一楼会议室 参与人员:窝窝头全体成员(王若愚因事请假) 设想和目标 我们的软件要解决什么问题?是否定义得很清楚?是否对典型用户和典型场景有清晰的描述 ...
- 《linux内核》课本第五章读书笔记
- 2013337朱荟潼 Linux第四章读书笔记——进程调度
第4章 进程调度 0. 总结 调度:调度是一个平衡的过程.一方面,它要保证各个运行的进程能够最大限度的使用CP:另一方面,保证各个进程能公平的使用CPU. 调度功能:决定哪个进程运行以及进程运行多长时 ...
- 框架-Spring
项目中都用到了Spring.Mybatis.SpringMVC框架,首先来谈一谈Spring框架,Spring框架以IOC.AOP作为主要思想. IOC----控制反转 IOC的全称为Inversio ...
- 12th final 发布评价II
1.约跑App——nice!:用户界面很是赏心悦目,给人一种很放松的感觉,与App的主题很配合,同时也在本周内把同学提出的bug都很好地完善了,而且采用了摄像头进行发布,整个发布过程清晰明朗不少.把约 ...
- linux 解压文件
原文:android之常用解压缩指令 .tar解包:tar xvf FileName.tar打包:tar cvf FileName.tar DirName ---------------------- ...