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:=10n:=0m:=i/n //错误,除数不能为0fmt.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)// outputerr3: [err2: [new error]]
err2 就是一个合法的被包装的 error,同样地,err3 也是一个被包装的 error,如此可以一直套下去
方式二:自定义 struct
type WarpError struct {msg stringerr 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)))// outputerr2: [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))// outputtruetrue
AS
这个和上面的 errors.Is 大体上是一样的,区别在于 Is 是严格判断相等,即两个 error 是否相等。
而 As 则是判断类型是否相同,并提取第一个符合目标类型的错误,用来统一处理某一类错误。
type ErrorString struct {s string}func (e *ErrorString) Error() string {return e.s}var targetErr *ErrorStringerr := fmt.Errorf("new error:[%w]", &ErrorString{s:"target err"})fmt.Println(errors.As(err, &targetErr))// outputtrue
自定义异常
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 mainimport ("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 mainimport ("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)}
