溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

go語(yǔ)言中的錯(cuò)誤處理機(jī)制

發(fā)布時(shí)間:2020-06-18 11:51:59 來(lái)源:億速云 閱讀:181 作者:鴿子 欄目:編程語(yǔ)言

基礎(chǔ)

錯(cuò)誤處理應(yīng)該是工程的一部分,Golang中的error是一個(gè)interface類型,如下:

type error interface {
	Error() string
}

凡是實(shí)現(xiàn)Error()方法的結(jié)構(gòu),都可以作為錯(cuò)誤處理。因此如果函數(shù)可能出現(xiàn)錯(cuò)誤,那么可以在返回值的最后,返回一個(gè)錯(cuò)誤,比如:

func foo() error {
	// ... do something
	return errors.New("foo error")
}

直接返回錯(cuò)誤

直接返回錯(cuò)誤,類似于直接返回字符串類型的錯(cuò)誤,或者錯(cuò)誤碼之類的。字符串類型的錯(cuò)誤,在基礎(chǔ)部分提到了。錯(cuò)誤碼相當(dāng)于Linux、C編程中的錯(cuò)誤碼,一般我們需要自己定義。舉個(gè)例子:

package mypkg

type ErrCode int

const (
	ERR1 = 1
	ERR2 = 2
	ERR3 = 3
)

func sub(a, b int) (int, ErrCode) {
	if b < 0 {
		return 0, ERR1
	} else if a < b {
		return 0, Err2
	} else if a < 0 {
		return 0, Err3
	}
	return a - b
}

這種類型的錯(cuò)誤,編寫(xiě)簡(jiǎn)單,但是有兩個(gè)缺陷:

1、外層如果想要使用錯(cuò)誤碼,則需要引入這個(gè)包,容易出現(xiàn)循環(huán)引用的情況。

2、如果包內(nèi)部修改返回的錯(cuò)誤碼類型,則外部使用到錯(cuò)誤碼的地方,都要進(jìn)行相應(yīng)的修改,破壞了封閉性。

對(duì)于第一個(gè)缺陷,可以使用一個(gè)第三方的包,專門(mén)存放錯(cuò)誤碼,這個(gè)方式值得商榷。永遠(yuǎn)不要通過(guò)判斷Error()方法返回的字符串的值,來(lái)進(jìn)行對(duì)應(yīng)的錯(cuò)誤處理?。?!

返回自定義類型的錯(cuò)誤

該方式可以返回自定義的類型,并通過(guò)斷言自定義類型,來(lái)進(jìn)行有關(guān)的錯(cuò)誤處理;自定義類型可以攜帶更多的信息,代碼實(shí)例:

package main

import (
	"errors"
	"fmt"
	"runtime/debug"
)

type MyError struct {
	Inner      error                  // 內(nèi)粗錯(cuò)誤
	Message    string                 // 自定義錯(cuò)誤信息
	StackTrace string                 // 堆棧信息
	Misc       map[string]interface{} //其它的一些數(shù)據(jù)
}

func (myError MyError) Error() string {
	return myError.Message
}

func wrapError(err error, msg string, msgArgs ...interface{}) MyError {
	return MyError{
		Inner:      err,
		Message:    fmt.Sprintf(msg, msgArgs),
		StackTrace: string(debug.Stack()),
		Misc:       make(map[string]interface{}),
	}
}

func Handle(key int) error {
	if key < 0 {
		return wrapError(errors.New("key < 0"), "This is an error test")
	}
	return nil
}

func main() {
	if err := Handle(-1); err != nil {
		if e, ok := err.(MyError); ok {
			fmt.Printf("Inner: %v, Message: %v, StackTrace: %v\n",
				e.Inner, e.Message, e.StackTrace)  // 這里輸出對(duì)應(yīng)的數(shù)據(jù)
		}
	}
}

這種方式處理問(wèn)題更加方便,但是仍然可能會(huì)有包循環(huán)引用的問(wèn)題。

隱藏內(nèi)部細(xì)節(jié)的錯(cuò)誤處理

上述兩種方式,可以適應(yīng)一些場(chǎng)景,不過(guò)都無(wú)法解決可能存在循環(huán)依賴的問(wèn)題。為此,我們使用github.com/pkg/errors的包來(lái)解決問(wèn)題,給出一個(gè)代碼實(shí)例。

func New(message string) error

如果有一個(gè)現(xiàn)成的error,我們需要對(duì)他進(jìn)行再次包裝處理,這時(shí)候有三個(gè)函數(shù)可以選擇。

//只附加新的信息
func WithMessage(err error, message string) error
//只附加調(diào)用堆棧信息
func WithStack(err error) error
//同時(shí)附加堆棧和信息
func Wrap(err error, message string) error

其實(shí)上面的包裝,很類似于Java的異常包裝,被包裝的error,其實(shí)就是Cause,在前面的章節(jié)提到錯(cuò)誤的根本原因,就是這個(gè)Cause。所以這個(gè)錯(cuò)誤處理庫(kù)為我們提供了Cause函數(shù)讓我們可以獲得最根本的錯(cuò)誤原因。

func Cause(err error) error {
	type causer interface {
		Cause() error
	}

	for err != nil {
		cause, ok := err.(causer)
		if !ok {
			break
		}
		err = cause.Cause()
	}
	return err
}

使用for循環(huán)一直找到最根本(最底層)的那個(gè)error。

以上就是關(guān)于golang中的錯(cuò)誤處理機(jī)制的詳細(xì)介紹的詳細(xì)內(nèi)容,更多請(qǐng)關(guān)注億速云其它相關(guān)文章!

向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI