Go 的异常错误处理只有Error,任何错误都可以直接返回,而不是使用try catch进行,如果函数在运行中出现异常我们应该把异常返回,如果没有则返回nil,且每次调用可能出现异常的函数时应主动进行检查做出反应。
// 定义异常 func fn(a int64) (b int64, err error) { if a == 1 { return 1, errors.New("this code Seems to have encountered some problems") } return 0, nil } // 处理异常 func handle() { b, err := fn(1) if err != nil { fmt.Println(err.Error()) } else { fmt.Println(b) } } 复制代码
在Go中出现异常不处理也不会影响代码流程的。
我们也可以在Go中自定义错误类型,异常是一个接口,error是接口类型,我们通过自定义一个结构体进而实现error接口来增加我们的错误信息
// 自定义的异常类 实现error接口 type MyError struct { code int32 message string } // 实现error接口的Error方法 func (e *MyError) Error() string { // 自定义异常信息 return fmt.Errorf("this program encure err, code=%d, message=%s", e.code, e.message).Error() } // 抛出异常 func TryErr(a int64) (int64, error) { if a == 1 { return 1, &MyError{-1, "fail"} // 抛出自定义的异常类 } return 0, nil } func fn() { i, e := TryErr(1) fmt.Println(i, e.Error()) }
我们需要对error 接口进行不同错误的实现进而判断做针对性处理,在日常开发中我们也经常使用
type CommonErr struct { code int32 message string } func (e *CommonErr) Error() string { return fmt.Errorf("this program encure err, code=%d, message=%s", e.code, e.message).Error() } type CommonErr1 struct { code int32 message string } func (e *CommonErr1) Error() string { return fmt.Errorf("this program encure err, code=%d, message=%s", e.code, e.message).Error() } // 判断错误进行处理 func dealErrByType(err error) { switch err.(type) { case *CommonErr: fmt.Println(err.Error()) case *CommonErr1: fmt.Println(err.Error()) } }
我们在开发中需要注意以下几个对于错误的处理
- 在返回值有多个的情况且有error,error应该在最后一个
- 错误值进行统一,而非随便定义
在Go的错误处理中,我们没有做任何处理程序依旧会走下去,很显然这样不太好,因此Go提供了一个panic函数用于终止代码执行。
func panic(interface{})
panic函数的参数是空接口类型可以接受任何类型的对象,一旦使用了panic函数就会让Go进程终止。
func test(a int64) (b int64) { panic(" test panic") return 1 } func fn() { test(1) time.Sleep(3 * time.Second) fmt.Print(1) }
上面的代码中我们能看到执行test函数时出现错误,后面的代码不在执行,为了防止这种情况,Go又提供了recover函数来捕获panic函数的异常
func recover() interface{}
recover函数用来获取panic函数的信息不过只能在延时调用defer语句调用函数中才可以使用
defer函数的作用就是延迟调用,等到函数返回的时候在调用,一个函数中可以包含多个,执行顺序是后入为主的顺序执行
func test(a,b,c int64) { defer func() { if a == 3 { fmt.Println(3) } }() defer func() { if b == 2 { fmt.Println(2) } }() defer func() { if c == 1 { fmt.Println(1) } }() } func fn() { test(3,2,1) }
我们通过defer结合recover函数进行使用一下
func fn() { defer func() { if err := recover(); err != nil { fmt.Println("Panic info is: ", err) } time.Sleep(3 * time.Second) fmt.Println("program done") }() panic("testPanic123") fmt.Println("after panic") }
defer总是会在fn函数结束之后才执行,那么 recover函数就能收集到panic发出来的异常信息并进行处理。
panic和recover函数在别的语言中就是try catch操作,但是他的作用比try catch大的多。
Go由于并没有检查时异常只有运行时异常,所以在写代码的时候我们就要尽可能的将你认为会出错的地方抛出来。
本文正在参加技术专题18期-聊聊Go语言框架