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. koa2 入门(1)koa-generator 脚手架和 mongoose 使用

    项目地址:https://github.com/caochangkui/demo/tree/koa2-learn 1 构建项目 1.1 安装koa-generator $ npm install -g ...

  2. [CF1019C]Sergey's problem[构造]

    题意 找出一个集合 \(Q\),使得其中的点两两之间没有连边,且集合中的点可以走不超过两步到达其他所有不在集合中的点.输出任意一组解. \(n\leq 10^6\) 分析 考虑构造,先从 \(1\) ...

  3. POJ1094——拓扑排序和它的唯一性

    比较模板的topological-sort题,关键在于每个元素都严格存在唯一的大小关系,而一般的拓扑排序只给出一个可能解,这就需要每趟排序的过程中监视它是不是总坚持一条唯一的路径. 算法导论里面的拓扑 ...

  4. 命令行启用IIS Express

    我们在调试WEB程序的时候可以把本地web程序挂载到本地IIS,然后访问程序,通过附加进程的方式(w3wp)来调试程序(个人非常喜欢的一种调试方式),还有一种比较传统的方式就是通过VS自带的F5来执行 ...

  5. ASP.NetCore2.0概览

      微软为了统一微软平台,造就了.netStandard,不管之前的Framework还是最新的.netCore都必须支持.netStandard标准来统一各个平台的开发api. 以下是之前的微软各个 ...

  6. 利用顺序栈解决括号匹配问题(c++)-- 数据结构

    题目: 7-1 括号匹配 (30 分)   给定一串字符,不超过100个字符,可能包括括号.数字.字母.标点符号.空格,编程检查这一串字符中的( ) ,[ ],{ }是否匹配. 输入格式: 输入在一行 ...

  7. kali linux 安装Nessus

    Nessus 介绍: Nessus 是目前全世界最多人使用的系统漏洞扫描与分析软件.总共有超过75,000个机构使用Nessus 作为扫描该机构电脑系统的软件. 下载Nessus,我的是64为,我选择 ...

  8. Nuxeo 认证绕过和RCE漏洞分析(CVE-2018-16341)

    简介 Nuxeo Platform是一款跨平台开源的企业级内容管理系统(CMS).nuxeo-jsf-ui组件处理facelet模板不当,当访问的facelet模板不存在时,相关的文件名会输出到错误页 ...

  9. HAOI2017 新型城市化 二分图的最大独立集+最大流+强连通缩点

    题目链接(洛谷):https://www.luogu.org/problemnew/show/P3731 题意概述:给出一张二分图,询问删掉哪些边之后可以使这张二分图的最大独立集变大.N<=10 ...

  10. Linux第七周学习总结——可执行程序的装载

    Linux第七周学习总结--可执行程序的装载 作者:刘浩晨 [原创作品转载请注明出处] <Linux内核分析>MOOC课程http://mooc.study.163.com/course/ ...