[Golang]-4 错误处理、Panic、Defer
Go 语言使用一个独立的·明确的返回值来传递错误信息的。这与使用异常的 Java 和 Ruby 以及在 C 语言中经常见到的超重的单返回值/错误值相比,
Go 语言的处理方式能清楚的知道哪个函数返回了错误,并能像调用那些没有出错的函数一样调用。
错误和异常
- 错误:指的是可能出现问题的地方出现了问题; 
 比如打开一个文件时失败,这种情况在人们的意料之中 ;
- 异常:指的是不应该出现问题的地方出现了问题; 
 比如引用了空指针,这种情况在人们的意料之外。可见,错误是业务过程的一部分,而异常不是 。
Golang中引入error接口类型作为错误处理的标准模式,如果函数要返回错误,则返回值类型列表中肯定包含error。
error处理过程类似于C语言中的错误码,可逐层返回,直到被处理。
案例
package main
import (
	"errors"
	"fmt"
)
// 按照惯例,错误通常是最后一个返回值并且是 error 类型,一个内建的接口。
func f1(arg int) (int, error) {
	if arg == 42 {
		// errors.New 构造一个使用给定的错误信息的基本error 值。
		return -1, errors.New("can't work with 42")
	}
	// 返回错误值为 nil 代表没有错误。
	return arg + 3, nil
}
// 通过实现 Error 方法来自定义 error 类型是可以的。这里使用自定义错误类型来表示上面的参数错误。
type argError struct {
	arg  int
	prob string
}
func (e *argError) Error() string {
	return fmt.Sprintf("%d - %s", e.arg, e.prob)
}
func f2(arg int) (int, error) {
	if arg == 42 {
		// 使用 &argError 语法来建立一个新的结构体,并提供了 arg 和 prob 这个两个字段的值。
		return -1, &argError{arg, "can't work with it"}
	}
	return arg + 3, nil
}
func main() {
	// 下面的两个循环测试了各个返回错误的函数。注意在 if行内的错误检查代码,在 Go 中是一个普遍的用法。
	// range 提供每项的索引和值。我们不需要索引,所以们使用空值定义符_来忽略它。有时候是需要这个索引的。
	for _, i := range []int{7, 42} {
		if r, e := f1(i); e != nil {
			fmt.Println("f1 failed:", e)
		} else {
			fmt.Println("f1 worked:", r)
		}
	}
	for _, i := range []int{7, 42} {
		if r, e := f2(i); e != nil {
			fmt.Println("f2 failed:", e)
		} else {
			fmt.Println("f2 worked:", r)
		}
	}
	// 你如果想在程序中使用一个自定义错误类型中的数据,你需要通过类型断言来得到这个错误类型的实例。
	_, e := f2(42)
	if ae, ok := e.(*argError); ok {
		fmt.Println(ae.arg)
		fmt.Println(ae.prob)
	}
}
输出结果:
f1 worked: 10
f1 failed: can't work with 42
f2 worked: 10
f2 failed: 42 - can't work with it
42
can't work with it
Golang中引入两个内置函数panic (['pænɪk]恐惧)和recover ([.ri'kʌvər]恢复)来触发和终止异常处理流程,同时引入关键字defer([dɪ'fɜr])来延迟执行defer后面的函数。
Panic
panic 意味着有些出乎意料的错误发生。通常我们用它来表示程序正常运行中不应该出现的,或者我们没有处理好的错误。
import "os"
func main() {
	// 我们将使用 panic 来检查预期外的错误。这个是为 panic 准备的例子。
	panic("a problem")
	// panic 的一个基本用法就是在一个函数返回了错误值但是我们并不知道(或者不想)处理时终止运行。
	// 这里是一个在创建一个新文件时返回异常错误时的panic 用法。
	_, err := os.Create("/tmp/file")
	if err != nil {
		panic(err)
	}
}
输出:
panic: a problem
goroutine 1 [running]:
main.main()
	/.../panic.go:10 +0x45
Defer
Defer 被用来确保一个函数调用在程序执行结束前执行。同样用来执行一些清理工作。 defer 用在像其他语言中的 ensure 和 finally用到的地方。
假设我们想要创建一个文件,向它进行写操作,然后在结束时关闭它。这里展示了如何通过 defer 来做到这一切。
import (
	"fmt"
	"os"
)
func main() {
	// 在 closeFile 后得到一个文件对象,我们使用 defer通过 closeFile 来关闭这个文件。
	// 这会在封闭函数(main)结束时执行,就是 writeFile 结束后。
	f := createFile("defer.txt")
	defer closeFile(f)
	writeFile(f)
}
func createFile(p string) *os.File {
	fmt.Println("creating")
	f, err := os.Create(p)
	if err != nil {
		panic(err)
	}
	return f
}
func writeFile(f *os.File) {
	fmt.Println("writing")
	fmt.Fprintln(f, "data")
}
func closeFile(f *os.File) {
	fmt.Println("closing")
	f.Close()
}
输出:
creating
writing
closing
明显,这个文件在写入后是已关闭的。
使用 defer+recover 来处理错误
import (
	"fmt"
)
func main() {
	// 使用defer + recover来捕获和处理异常
	defer func() {
		// recover 是内置函数,可以捕获异常
		err := recover()
		if err != nil {
			fmt.Println("err=", err)
		}
	}()
	num1 := 10
	num2 := 0
	res := num1 / num2
	fmt.Println("res=", res)
}
输出:
err= runtime error: integer divide by zero
参考文章:
- Golang错误和异常处理的正确姿势:https://www.cnblogs.com/zhangboyu/p/7911190.html
[Golang]-4 错误处理、Panic、Defer的更多相关文章
- Golang错误处理函数defer、panic、recover、errors.New介绍
		在默认情况下,当发生错误(panic)后,程序就会终止运行 如果发生错误后,可以捕获错误,并通知管理人员(邮件或者短信),程序还可以继续运行,这当然无可厚非 errors.New("错误信息 ... 
- 【GoLang】panic defer recover 深入理解
		唉,只能说C程序员可以接受go的错误设计,相比java来说这个设计真的很差劲! 我认为知乎上说的比较中肯的: 1. The key lesson, however, is that errors ar ... 
- 『GoLang』错误处理
		Go 没有像 Java 和 .NET 那样的 try/catch 异常机制:不能执行抛异常操作.但是有一套 defer-panic-and-recover 机制. Go 的设计者觉得 try/catc ... 
- [golang note] 错误处理
		错误处理 • 错误处理的标准模式 √ golang错误处理的标准模式:error接口. √ golang函数如果要返回错误,规范上是将error作为多返回值中的最后一个,但这并非是强制要求. ▶ er ... 
- GoLang之错误处理
		错误处理 error Go语言引入了一个错误处理的标准模式,即error接口,该接口定义如下: type error interface { Error() string } 对于大多数函数,如果要返 ... 
- 个人犯的一个golang routine错误
		这个其实不是错误,2个写法没有区别.-2015.11.22 认识golang也不少时间了,也做过几个项目.最近发现之前用golang写的一个服务,内存涨得比较快,一直没找出来原因来.今天把疑惑发到群里 ... 
- golang error错误处理
		error定义 数据结构 go语言error是一普通的值,实现方式为简单一个接口. // The error built-in interface type is the conventional i ... 
- 解决Ubuntu启动错误——kernel panic not syncing vfs unable to mount root fs on unknown-block 0 0 – error
		最近在倒腾Ubuntu,然后想着怎么美化一下界面,于是照着网上的教程整了一下Flatabulous这个软件,然后好像/boot就满了.关机之后再开机就出现了如题所述的错误,无法开机,也无法进入reco ... 
- golang处理错误的艺术
		golang中关键API的调用都会在最后返回err(golang多值返回). 调用者可以选择处理, 或者不处理该err, 或原装返回给上一层的调用者. golang中的err是error类型, typ ... 
随机推荐
- RecyclerView 源码分析(二) —— 缓存机制
			在前一篇文章 RecyclerView 源码分析(一) -- 绘制流程解析 介绍了 RecyclerView 的绘制流程,RecyclerView 通过将绘制流程从 View 中抽取出来,放到 Lay ... 
- 【Android】编译报错 Annotation processors must be explicitly declared now 解决方案
			问题 在网上下载一个demo,因为版本久远,里面添加了本地 Butter Knife 的jar包,在编译时报错 Annotation processors must be explicitly dec ... 
- MySQL ---- 锁知识
			锁 我们知道mysql中支持很多个存储引擎,在不同的存储引擎下所能支持的锁是不同的,我们通过MyISAM和InnoDB来进行一下对比. 表级锁定(table-level)  表级别的锁定是MySQL ... 
- 文件的上传/下载+在线游览(转化html)--不需要在线插件//自己写的小方法
			1 /// <summary> 2 /// 文件上传下载帮助类 3 /// </summary> 4 public static class FileHelper 5 { 6 ... 
- Vue中:error  'XXXXX' is not defined  no-undef解决办法
			Vue中:error 'XXXXX' is not defined no-undef解决办法 报错内容: × Client Compiled with some errors in 7.42s √ S ... 
- 消息中间件——rocketmq环境配置
			产生原因 RocketMQ概述 RocketMQ 是一款分布式.队列模型的消息中间件,具有以下特点: 能够保证严格的消息顺序 提供丰富的消息拉取模式 高效的订阅者水平扩展能力 实时的消息订阅机制 亿级 ... 
- 动态传参,命名空间,嵌套,gloabal,nonlocal
			一.动态传参 动态接受位置参数: *参数名 def eat(*food): print(food) #多个参数传递进去,收到的内容是元祖tuple eat("盖浇饭", &quo ... 
- JDBC基础:JDBC快速入门,JDBC工具类,SQL注入攻击,JDBC管理事务
			JDBC基础 重难点梳理 一.JDBC快速入门 1.jdbc的概念 JDBC(Java DataBase Connectivity:java数据库连接)是一种用于执行SQL语句的Java API,可以 ... 
- Docker+Prometheus+Alertmanager+Webhook钉钉告警
			Docker+Prometheus+Alertmanager+Webhook钉钉告警 1.环境部署 1.1 二进制部署 1.2 docker部署 1.2.1 webhook 1.2.2 alertma ... 
- c++复习笔记(2)
			1. 类与对象 类的声明与结构,数据成员和成员函数. 成员函数可以在类外被定义.但是必须在类内声明. 封装:protect--允许类成员和派生类成员访问. 构造函数之外,还有一种初始化类成员的方法:参 ... 
