1、GO中Panic是一种系统级别的异常,一旦出现回终端程序的运行,来自运行时。并且当我们手动调用panic()
函数的时候也会触发这个异常。用于严重错误,此时不管出现在哪里Panic都会直接结束程序(除非进行恢复)
2、手动触发panic()
如下:
func main(){
//do something
panic("panic happend !! ")
//do sonmething will not be excute
}
当panic()
触发的时候,会立即在当前GO程中执行一个 defer1 ,并且其实际会输出详细的堆栈调用日志。
1、Error
在GO中默认使用返回值的方法进行返回,要不你接受这个错误进行处理,要不使用_
匿名接收这个错误不处理。
nil
:表示没有错误2、手动抛出一个error
func main(){
throwError()
}
func throwError() (err error ){
//do something
return errors.New("this is a new error")
}
3、errors
包
1、errors
源码如下:
package errors
// New returns an error that formats as the given text.
// Each call to New returns a distinct error value even if the text is identical.
func New(text string) error {
return &errorString{text}
}
// errorString is a trivial implementation of error.
type errorString struct {
s string
}
// output error detail
func (e *errorString) Error() string {
return e.s
}
根据errors.go
我们可以按照他的方法自定义一个错误类型并且实现错误error
接口,实现自定义错误类型。
// error 接口
type error interface {
Error() string
}
官方实例代码:
package errors_test
import (
"fmt"
"time")
// MyError is an error implementation that includes a time and message.
type MyError struct {
When time.Time
What string
}
func (e MyError) Error() string {
return fmt.Sprintf("%v: %v", e.When, e.What)
}
func oops() error {
return MyError{
time.Date(1989, 3, 15, 22, 30, 0, 0, time.UTC),
"the file system has gone away",
}}
func Example() {
if err := oops(); err != nil {
fmt.Println(err)
} // Output: 1989-03-15 22:30:00 +0000 UTC: the file system has gone away
}
参考:
实际上包裹了一个
error
错误链,具体原理如下:
Unwrap(err error) error :获取内层的error,返回错误根本原因
return fmt.Errorf("add error info: %+v, origin error: %w", "other info", err)
func Unwrap(err error) error {
//断言转化 err类型为一个实现了Unwarp()方法的interface对象
u, ok := err.(interface {
Unwrap() error
})
//断言失败
if !ok {
return nil
}
//继续解包
return u.Unwrap()
}
Is(err, target error) bool :查看调用链是否与包含target错误
源码:
func Is(err, target error) bool {
if target == nil {
return err == target
}
//类型是否可比
isComparable := reflectlite.TypeOf(target).Comparable()
for {
//与目标 err相同
if isComparable && err == target {
return true
}
//递归继续向下查找错误链上是否包含指定目标错误
if x, ok := err.(interface{ Is(error) bool }); ok && x.Is(target) {
return true
}
//解包到最后依然不存在,没有找到
if err = Unwrap(err); err == nil {
return false
}
}}
As(err error, target interface{}) bool : 剥离到给定target并将target设置到属性中去
源码:
func As(err error, target any) bool {
//校验转化目标是否为空
//判空
if target == nil {
panic("errors: target cannot be nil")
}
//拿到value
val := reflectlite.ValueOf(target)
//拿到value的实际类型reflect.type
typ := val.Type()
//实际目标类型不是一个指针类型,或者是一个空指针类型
if typ.Kind() != reflectlite.Ptr || val.IsNil() {
panic("errors: target must be a non-nil pointer")
}
//取出指针地址指向的对象
targetType := typ.Elem()
//判断其类是不是一个接口类型,以及是否实现了这个错误类型
if targetType.Kind() != reflectlite.Interface && !targetType.Implements(errorType) {
panic("errors: *target must be interface or implement error")
}
//校验待转化错误是否为空
for err != nil {
//判断是否可以将err分配到目标对象
if reflectlite.TypeOf(err).AssignableTo(targetType) {
//使用值进行设置到目标对象
val.Elem().Set(reflectlite.ValueOf(err))
return true
}
//err实现了As(any) bool方法断言成功并且执行方法进行转化
if x, ok := err.(interface{ As(any) bool }); ok && x.As(target) {
return true
}
//继续剥掉一层error看内部是否与给定匹配
err = Unwrap(err)
}
return false
}
在Panic错误中一半使用recover函数进行恢复整个已经崩溃的程序进程,但是必须在defer
中进行调用,才会生效。并且在函数调用的过程中可以在每个函数中都抛出panic
逐层向外,直到不能捕获就会结束。
使用方法:
func main(){
panicTest()
}
func panicTest(){
//do thomething
//捕获Panic
defer func (){
if err:= recover(); err != nil{
//deal error
}
}
}
在GO语言中不存在传统意义上面try -catch
语句,其设计思想如下:
nil
if
进行捕获异常进行处理err,ans = ErrorDemo()
if err != nil{
//处理异常
}
#todo
defer_语句会将其后面跟随的语句进行延迟处理,在 defer 归属的函数即将返回时,将延迟处理的语句按 defer 的逆序进行执行(多个执行入栈,出栈) ↩︎