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 异常处理 ...
随机推荐
- centos7 部署 nginx+tomcat+MariaDB 环境并安装安全狗,使用natapp隧道
jdk安装: -openjdk 参考:https://blog.csdn.net/dhr201499/article/details/81626466 tomcat安装: 使用版本:8.5.37 参考 ...
- java监听器(Listener)学习笔记
现在来说说Servlet的监听器Listener,它是实现了javax.servlet.ServletContextListener 接口的服务器端程序,它也是随web应用的启动而启动,只初始化一次, ...
- LeetCode Search for a Range (二分查找)
题意 Given a sorted array of integers, find the starting and ending position of a given target value. ...
- kubernetes 网络故障遇见的坑
1.记录一下自己搭建kubernetes 集群遇见的坑. 过程是我学技术以来最大的bug,处处都是坑,稍微写成一点, 就完全起不来, 起不来之后, 还找不到故障点, 郁闷之极. 后续会慢慢分享给大家. ...
- 如何在Windows Server 2003搭建Windows+iis+asp+access环境
前提系统盘镜像要加载进来方案一:开始->管理您的服务器->添加或删除角色->下一步->自定义配置->下一步->选择应用程序服务器(IIS,ASP.NET)-> ...
- python 游戏(井字棋)
1. 游戏思路和流程图 实现功能,现实生活中的井字棋玩法 游戏流程图 2. 使用模块和游戏提示 import random def game_info(): print('欢迎来到井字棋游戏') pr ...
- 使用不同的namespace让不同的kafka/Storm连接同一个zookeeper
背景介绍: 需要部署2个kafka独立环境,但是只有一个zookeeper集群. 需要部署2个独立的storm环境,但是只有一个zookeeper集群. ----------------------- ...
- Beta 冲刺 四
团队成员 051601135 岳冠宇 031602629 刘意晗 031602248 郑智文 031602330 苏芳锃 031602234 王淇 照片 项目进展 岳冠宇 昨天的困难 数据交换比较复杂 ...
- Centos7 安装netcat
1.下载 下载地址:https://sourceforge.net/projects/netcat/files/netcat/0.7.1/ 下载的是netcat-0.7.1.tar.gz版本 2.安装 ...
- [日常工作] 并行计算引发Microsoft.jscript.ni.dll的内存溢出问题的分析解决. .net framework 的版本说明
1. 性能组进行 单点性能测试时发现 商务智能的 并行分析有问题. 效率很低, 开发人员查看iis 的日志 发现错误原因是 Microsoft.jscript.ni.dll 有内存溢出的问题 开发人员 ...