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的更多相关文章

  1. 【GoLang】panic defer recover 深入理解

    唉,只能说C程序员可以接受go的错误设计,相比java来说这个设计真的很差劲! 我认为知乎上说的比较中肯的: 1. The key lesson, however, is that errors ar ...

  2. GO_05_2:Golang 中 panic、recover、defer 的用法

     函数 defer 1. 它的执行方式类似其他语言中的折构函数,在函数体执行结束后按照调用顺序的 相反顺序 逐个执行 2. 即使函数发生 严重错误 也会被执行,类似于 java 中 try{...} ...

  3. Golang的panic和recover

    panic 关键字panic的作用是制造一次宕机,宕机就代表程序运行终止,但是已经“生效”的延迟函数仍会执行(即已经压入栈的defer延迟函数,panic之前的). 为什么要制造宕机呢?是因为宕机不容 ...

  4. golang之panic,recover,defer

    defer,recover: 运行时恐慌一旦被引发,就会向调用方传播直至程序崩溃. recover内建函数用于“拦截”运行时恐慌,可以使当前的程序从恐慌状态中恢复并重新获得流程控制权. recover ...

  5. GOLANG错误处理最佳方案errors wrap, Defer, Panic, and Recover

    Simple error handling primitives:        https://github.com/pkg/errors Defer, Panic, and Recover:    ...

  6. Golang 高效实践之defer、panic、recover实践

    前言 我们知道Golang处理异常是用error返回的方式,然后调用方根据error的值走不同的处理逻辑.但是,如果程序触发其他的严重异常,比如说数组越界,程序就要直接崩溃.Golang有没有一种异常 ...

  7. Golang错误处理函数defer、panic、recover、errors.New介绍

    在默认情况下,当发生错误(panic)后,程序就会终止运行 如果发生错误后,可以捕获错误,并通知管理人员(邮件或者短信),程序还可以继续运行,这当然无可厚非 errors.New("错误信息 ...

  8. golang错误处理机制:panic与recover

    原文地址:http://www.niu12.com/article/14 panic知识点 package main import ( "fmt" "github.com ...

  9. panic和recover的使用规则

    转自个人博客 chinazt.cc 在上一节中,我们介绍了defer的使用. 这一节中,我们温习一下panic和recover的使用规则. 在golang当中不存在tye ... catch 异常处理 ...

随机推荐

  1. 校内模拟赛 Label

    题意: n个点m条边的无向图,有些点有权值,有些没有.边权都为正.给剩下的点标上数字,使得$\sum\limits_{(u,v)\in E}len(u,v) \times (w[u] - w[v]) ...

  2. VS2010带不出System.Data.OracleClient这个引用的解决方案

    在使用VS2010的时候有时会带不出System.Data.OracleClient这个引用,可以使用以下解决方法: 右击项目的属性,在弹出窗口中有一个“目标框架”下拉框选项,默认会是.NET FRA ...

  3. kubeadm安装K8S单master双节点集群

    宿主机:master:172.16.40.97node1:172.16.40.98node2:172.16.40.99 # 一.k8s初始化环境:(三台宿主机) 关闭防火墙和selinux syste ...

  4. DRF01

    1.web应用模式 在web开发中有两种应用模式: 1)前后端不分离 2)前后端分离 2.api接口 为了在团队内部形成共识.防止个人习惯差异引起的混乱,我们需要找到一种大家都觉得很好的接口实现规范, ...

  5. PAT甲题题解-1054. The Dominant Color (20)-排序/map

    原本用map,发现超时了,后来便先用数组存储排个序,最后for一遍统计每种颜色出现的次数(每种颜色的首位索引相减+1),找出最多的即可. #include <iostream> #incl ...

  6. Linux内核分析作业第三周

    一.实验楼实验 使用实验楼的虚拟机打开shell 1 cd LinuxKernel/ 2 qemu -kernel linux-3.18.6/arch/x86/boot/bzImage -initrd ...

  7. windows 64bit 服务器下安装32位oracle database 11g 问题集

    1.中文乱码 问题描述: 利用vs2008调试的时候正常,发布到IIS8.5上的时候,当查询语句中包含中文的时候会乱码,比如"select * from tb where name='小s' ...

  8. 注解Annotation实现原理与自定义注解例子

    什么是注解? 对于很多初次接触的开发者来说应该都有这个疑问?Annontation是Java5开始引入的新特征,中文名称叫注解.它提供了一种安全的类似注释的机制,用来将任何的信息或元数据(metada ...

  9. Spring所需的Jar包下载

    作者:zhidashang 来源:CSDN 原文:https://blog.csdn.net/zhidashang/article/details/78706027 版权声明:本文为博主原创文章,转载 ...

  10. psp进度统计

    每周例行报告 本周PSP 类别 任务 开始时间 结束时间 被打断时间 总计工作时间    11月8日 代码 参与团队项目 10:13 11:30 0 77min 写博客 词频统计总结 13:35 14 ...