go的error
func main() {
map1 :=make(map[int]string)
map1[0]="a"
map1[1]="b"
val,ok := map1[0]
if ok{
fmt.Println(val)
}else {
fmt.Println("key为0不在map1中")
}
}
异常处理
func test(){
defer func() {
if err:=recover();err!=nil{ //err不等于零值,说明发生了异常
fmt.Println("err=",err)
fmt.Println("发生错误我要做什么处理")
}
}()
i:=10
n:=0
m:=i/n //错误,除数不能为0
fmt.Println(m)
}
func main() {
test()
fmt.Println("main函数")
}
创建一个被包装的 error
方式一:fmt.Errorf
使用 %w 参数返回一个被包装的 error
err1 := errors.New("new error")
err2 := fmt.Errorf("err2: [%w]", err1)
err3 := fmt.Errorf("err3: [%w]", err2)
fmt.Println(err3)
// output
err3: [err2: [new error]]
err2 就是一个合法的被包装的 error,同样地,err3 也是一个被包装的 error,如此可以一直套下去
方式二:自定义 struct
type WarpError struct {
msg string
err error
}
func (e *WarpError) Error() string {
return e.msg
}
func (e *WrapError) Unwrap() error {
return e.err
}
之前看过源码的同学可能已经知道了,这就是 fmt/errors.go 中关于 warp 的结构。
就,很简单。自定义一个实现了 Unwrap 方法的 struct 就可以了。
拆开一个被包装的 error
errors.Unwrap
err1 := errors.New("new error")
err2 := fmt.Errorf("err2: [%w]", err1)
err3 := fmt.Errorf("err3: [%w]", err2)
fmt.Println(errors.Unwrap(err3))
fmt.Println(errors.Unwrap(errors.Unwrap(err3)))
// output
err2: [new error]
new error
错误比较
IS
当多层调用返回的错误被一次次地包装起来,我们在调用链上游拿到的错误如何判断是否是底层的某个错误呢?
它递归调用 Unwrap 并判断每一层的 err 是否相等,如果有任何一层 err 和传入的目标错误相等,则返回 true。
err1 := errors.New("new error")
err2 := fmt.Errorf("err2: [%w]", err1)
err3 := fmt.Errorf("err3: [%w]", err2)
fmt.Println(errors.Is(err3, err2))
fmt.Println(errors.Is(err3, err1))
// output
true
true
AS
这个和上面的 errors.Is 大体上是一样的,区别在于 Is 是严格判断相等,即两个 error 是否相等。
而 As 则是判断类型是否相同,并提取第一个符合目标类型的错误,用来统一处理某一类错误。
type ErrorString struct {
s string
}
func (e *ErrorString) Error() string {
return e.s
}
var targetErr *ErrorString
err := fmt.Errorf("new error:[%w]", &ErrorString{s:"target err"})
fmt.Println(errors.As(err, &targetErr))
// output
true
自定义异常
func read(str string) (err error){
if str!="aaa"{
return errors.New("传的值不等于aaa!")//自定义异常
}else {
return nil
}
}
func test1() {
err :=read("aaa")
if err!=nil{
panic(err)//err!=nil说明发生了异常,用panic()输出异常并终止程序
}
fmt.Println("test1函数继续执行")
}
func main() {
test1()
fmt.Println("main函数继续执行")
}
规则
同步执行,在panic发生的方法的祖辈层都能处理
package main
import (
"fmt"
"time"
)
func haha1() int {
a:= []int{1,2,3}
return a[3]
}
func hehe() {
// 放在main中也行
defer func() {
if err:=recover();err!=nil{
fmt.Println("异常处理")
}
}()
haha1()
}
func main() {
hehe()
time.Sleep(time.Second)
}
异步执行,必须得在被go 的方法中
package main
import (
"fmt"
"time"
)
func haha1() int {
a:= []int{1,2,3}
return a[3]
}
func hehe() {
defer func() {
if err:=recover();err!=nil{
fmt.Println("异常处理")
}
}()
haha1()
}
func main() {
go hehe()
time.Sleep(time.Second)
}