Go的错误、异常处理机制

错误和异常的区别

  • 错误指的是可能出现问题的地方出现了问题,比如打开一个文件时失败,这种情况在人们的意料之中 ;而异常指的是不应该出现问题的地方出现了问题,比如引用了空指针,这种情况在人们的意料之外。可见,错误是业务过程的一部分,而异常不是 。

  • 错误和异常从Golang机制上讲,就是error和panic的区别。

  • Golang错误和异常是的互相转换的:

    错误转异常,比如程序逻辑上尝试请求某个URL,最多尝试三次,尝试三次的过程中请求失败是错误,尝试完第三次还不成功的话,失败就被提升为异常了。

    异常转错误,比如panic触发的异常被recover恢复后,将返回值中error类型的变量进行赋值,以便上层函数继续走错误处理流程。

  • Go语言中,一旦某一个协程发生了panic而没有被recover,那么会导致整个go程序都会终止

关于异常与错误设计原则

错误设计:

  • 如果失败原因只有一个,则返回bool
  • 如果失败原因超过一个,则返回error
  • 如果没有失败原因,则不返回bool或error
  • 如果重试几次可以避免失败,则不要立即返回bool或error

异常设计:

  • 在程序开发阶段,坚持速错,让程序异常崩溃
  • 在程序部署后,应恢复异常避免程序终止
  • 对于不应该出现的分支,使用异常处理

Go内置error接口处理用来处理错误

// The error built-in interface type is the conventional interface for
// representing an error condition, with the nil value representing no error.
type error interface {
	Error() string
}

内置new实现接口的实现

// 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
}

func (e *errorString) Error() string {
	return e.s
}

Go内置异常处理函数

  • Go内置函数panic和recover来触发和终止异常处理流程,同时引入关键字defer来延迟执行defer后面的函数。
  • defer延迟函数总是在异常panic或者正常return前返回
    	func main(){
    	defer fmt.Println(123)
    	defer fmt.Println(456)
    	panic("panic")
    }
    /*
    output:
    456
    123
    panic: panic
    */
    
  • panic是函数时,总是先执行;之后才会执行defer函数,最后返回panic
    	func main(){
    	defer fmt.Println(123)
    	defer fmt.Println(456)
    	panic(test())
    }
    func test()string{
    	fmt.Println("akjfjk")
    	return "test"
    }
    /*
    output:
    akjfjk
    456
    123
    panic: test
    */
    
    可以在defer中通过recover关键字恢复我们的panic,将之处理后转化为一个错误并打印(异常转错误)
    func TestDeferAndRecover(){
    defer func(){
        if err:=recover(); err != nil{
            fmt.Println("err is:",err)
        }
    }()    
        panic("panic has happended")
    }
    /*
    output:
    err is: panic has happended
    */
    
    

Go异常错误处理案例

开始代码

func divi(x,y int) (int,error){
	if y == 0{
		return 0,errors.New("y can`t be zero")
	}
	z := x / y
		return z ,nil
}
/*
divi(1,0)
output:
0 y can`t be zero
*/

当没有考虑到y不可以为零时;可以使用recover来捕捉panic,defer来延迟执行;作为错误来返回(避免异常导致整个程序Down掉)

func divi(x,y int) (z int,err error){
	defer func() {
		if e := recover();e!=nil{
			err =e.(error)
		}
	}()
	z = x / y
	return z ,nil
}
/*
output:
0 runtime error: integer divide by zero
*/

自定义错误类型

首先需要实现error这个接口类

type DIYerror struct{
	e string
	param string
}

func (d *DIYerror)Error()string{
	obj:= bytes.Buffer{}
	obj.WriteString("err is:")
	obj.WriteString(d.e)
	obj.WriteString("param is:")
	obj.WriteString(d.param)
	return obj.String()
}

func divi(x,y int) (z int,err error){
	if y == 0 {
		return 0,&DIYerror{
			e: "y can`t be 0",
			param: strings.Join([]string{strconv.Itoa(x),strconv.Itoa(y)},","),
		}
	}
	z = x / y
	return z ,nil
}
/*
output;
0 err is:y can`t be 0param is:1,0
*/

猜你喜欢

转载自blog.csdn.net/wzb_wzt/article/details/107741624