golangでエラーを処理する方法

青灯夜游
リリース: 2022-12-26 17:44:42
オリジナル
5830 人が閲覧しました

Golang には通常、エラー センチネル (センチネル エラー)、エラー タイプ アサーション、エラー コール スタックの記録という 3 つのエラー処理メソッドがあります。エラーセンチネルとは、エラー処理分岐の判定条件として特定の値を持つ変数を使用することを指します。エラー タイプは、エラー処理ロジックをルーティングするために使用され、エラー監視と同じ効果があります。タイプ システムは、エラー タイプの一意性を提供します。エラー ブラック ボックスとは、エラーの種類をあまり気にせず、エラーを上位層に返すことを指します。アクションを実行する必要がある場合、エラーの種類ではなくエラーの動作についてアサーションを行う必要があります。

golangでエラーを処理する方法

このチュートリアルの動作環境: Windows 7 システム、GO バージョン 1.18、Dell G3 コンピューター。

Golang は try-catch のようなエラー処理機構を提供せず、設計レベルで C 言語スタイルのエラー処理を採用し、関数の戻り値を通じてエラー情報を返します。具体的な例は次のとおりです。 :

func ReturnError() (string, error) {
	return "", fmt.Errorf("Test Error")
}

func main() {
	val, err := ReturnError()
	if err != nil {
		panic(err)
	}
	fmt.Println(val)
}
ログイン後にコピー

上記の例は、基本的なエラー処理の例です。運用環境で実行されるコール スタックは多くの場合非常に複雑で、返される error もさまざまです。多くの場合、次のことが必要です。 return エラー メッセージによって、特定のエラー処理ロジックが決まります。

Golang には通常、エラー センチネル (Sentinel Error)、エラー タイプ アサーション (Error Type Asseration)、エラー コール スタックの記録という 3 つのエラー処理メソッドがあります。

Error Sentinel (Sentinel Error)

Sentinel とは、エラー処理分岐の判定条件として特定の値を持つ変数を使用することを指します。一般的なアプリケーション シナリオには、# が含まれます。 gorm.##gorm.RecordNotFounded および Redis ライブラリ内の redis.NIL

Golang は同じ型の変数を比較でき、インターフェイス変数はインターフェイスが指すポインターのアドレスを比較します。したがって、

error 型変数が同じアドレスを指している場合に限り、2 つの変数は等しくなりますが、それ以外の場合は等しくありません。

var ErrTest = errors.New("Test Error")

err := doSomething()
if err == ErrTest{
	// TODO: Do With Error
}
ログイン後にコピー

Sentinel を使用する場合、次の問題があります。問題は 2 つあります:

1. コード構造が柔軟ではなく、分岐処理では

== しか使用できません。または ! = 判断してください このままではスパゲッティのようなコードが書きやすくなります。

var ErrTest1 = errors.New("ErrTest1")
var ErrTest2 = errors.New("ErrTest1")
var ErrTest3 = errors.New("ErrTest1")
……
var ErrTestN = errors.New("ErrTestN")
……
if err  == ErrTest1{
	……
} else if err == ErrTest2{
	……
}else if err == ErrTest3{
	……
}
……
else err == ErrTestN{
	……
}
ログイン後にコピー

2. センチネル変数の値は変更できません。それ以外の場合はロジック エラーが発生します。上記の golang 記述メソッドのエラー センチネルは変更でき、次の方法で解決できます。 ##
type Error string

func (e Error) Error() string { return string(e) }
ログイン後にコピー

3. センチネル変数はこれにより非常に強い結合が発生し、インターフェイスで新しいエラーが吐き出されることで、ユーザーはそれに応じてコードを変更し、新しい処理エラーを作成することになります。

上記のソリューションと比較すると、Error Sentinel には、変数ではなくインターフェイスに依存する、より洗練されたソリューションがあります。

var ErrTest1 = errors.New("ErrTest1")

func IsErrTest1(err error) bool{
  return err == ErrTest1
}
ログイン後にコピー

エラー タイプ

エラー タイプは、エラー処理ロジックのルーティングに使用され、エラー監視と同じ効果があります。型システムは、エラー タイプの一意性を提供します。使用方法は次のとおりです:

type TestError {
}
func(err *TestError) Error() string{
	return "Test Error"
}
if err, ok := err.(TestError); ok {
	//TODO 错误分支处理
}

err := something()
switch err := err.(type) {
case nil:
        // call succeeded, nothing to do
case *TestError:
        fmt.Println("error occurred on line:", err.Line)
default:
// unknown error
}
ログイン後にコピー

センチネルと比較して、エラー タイプの不変性変更は良好であり、

switch

を使用してエレガントなルーティング戦略を提供できます。しかし、これではユーザーがパッケージへの過度の依存を避けることができなくなります。 インターフェイスを使用してより複雑で多様なエラーをスローするには、呼び出し元のコードを変更する必要があります。

エラー ブラック ボックス (エラー インターフェイスに依存)

エラー ブラック ボックスとは、エラーの種類をあまり考慮せず、エラーを上位層に返すことを指します。アクションが必要な場合は、エラーの種類ではなく、エラーの動作についてアサーションを行ってください。

func fn() error{
	x, err := Foo()
	if err != nil {
		return err
	}
}

func main(){
	err := fn()
	if IsTemporary(err){
		fmt.Println("Temporary Error")
	}
}

type temporary interface {
        Temporary() bool
}
 
// IsTemporary returns true if err is temporary.
func IsTemporary(err error) bool {
        te, ok := err.(temporary)
        return ok && te.Temporary()
}
ログイン後にコピー

このようにして、1. インターフェイス間の依存関係は直接分離され、2. エラー処理ルーティングはエラー タイプとは関係ありませんが、特定の動作に関連付けられ、エラー タイプの拡大を回避します。

まとめ

エラーセンチネルとエラータイプでは過剰な依存問題は避けられない エラーブラックボックスのみがエラータイプ判定の処理ロジックから問題を変更できる(変数) to 不正行為を判断するため。したがって、エラーを処理するには 3 番目の方法を使用することをお勧めします。

ここで一文追加する必要があります。

ブラックボックス処理でエラーを返すというのは、エラーの存在を無視したり、直接無視したりするわけではありませんが、エラーを適切に処理する必要があります。適切な場所。このプロセスでは、

errorsWrapZaplogging などを使用して、レイヤーごとにエラーが返されるときに呼び出し側リンクのコンテキスト情報を記録できます。 。

func authenticate() error{
	return fmt.Errorf("authenticate")
}

func AuthenticateRequest() error {
	err := authenticate()
	// OR logger.Info("authenticate fail %v", err)
	if err != nil {
		return errors.Wrap(err, "AuthenticateRequest")
	}
	return nil
}

func main(){
	err := AuthenticateRequest()
	fmt.Printf("%+v\n", err)
	fmt.Println("##########")
	fmt.Printf("%v\n", errors.Cause(err))
}

// 打印信息
authenticate
AuthenticateRequest
main.AuthenticateRequest
	/Users/hekangle/MyPersonProject/go-pattern/main.go:17
main.main
	/Users/hekangle/MyPersonProject/go-pattern/main.go:23
runtime.main
	/usr/local/Cellar/go@1.13/1.13.12/libexec/src/runtime/proc.go:203
runtime.goexit
	/usr/local/Cellar/go@1.13/1.13.12/libexec/src/runtime/asm_amd64.s:1357
##########
authenticate
ログイン後にコピー
【関連する推奨事項: Go ビデオ チュートリアル 、

プログラミング教育 ]

以上がgolangでエラーを処理する方法の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

ソース:php.cn
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
最新の問題
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート