Golang 오류 처리 메커니즘

14326 단어 Go 언어 노트

기초


오류 처리 시 공정의 일부분Golangerror 유형은 다음과 같습니다.
type error interface {
	Error() string
}

무릇 실현interface 방법의 구조는 모두 오류로 처리할 수 있다.따라서 함수에 오류가 발생할 수 있다면, 반환 값의 마지막에 오류를 반환할 수 있습니다. 예를 들어 다음과 같습니다.
func foo() error {
	// ... do something
	return errors.New("foo error")
}

오류로 바로 돌아가기


문자열 형식의 오류나 오류 코드 같은 오류를 직접 되돌려줍니다.문자열 형식의 오류는 기초 부분에서 언급되었습니다.오류 코드는 Linux C 프로그래밍의 오류 코드와 같으며, 일반적으로 우리는 스스로 정의해야 한다.예:
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
}

이러한 유형의 오류는 작성이 간단하지만 두 가지 결함이 있습니다.
  • 외부에서 오류 코드를 사용하려면 이 패키지를 도입해야 하기 때문에 순환 인용이 발생하기 쉽다
  • 패키지 내부에서 오류 코드 유형을 수정하면 외부에서 오류 코드를 사용하는 곳은 상응하는 수정을 해야 하며 폐쇄성을 파괴한다
  • 첫 번째 결함에 대해 제3자의 가방을 사용하여 오류 코드를 전문적으로 보관할 수 있는데 이 방식은 의논할 가치가 있다.Error () 방법으로 되돌아오는 문자열의 값을 판단하여 대응하는 오류 처리를 하지 마십시오!!!

    사용자 정의 유형 오류 반환


    이 방식은 사용자 정의 유형을 되돌려주고 사용자 정의 유형을 단언함으로써 관련 오류 처리를 할 수 있다.사용자 정의 유형은 더 많은 정보를 가져올 수 있습니다. 코드 실례:
    package main
    
    import (
    	"errors"
    	"fmt"
    	"runtime/debug"
    )
    
    type MyError struct {
    	Inner      error                  //  
    	Message    string                 //  
    	StackTrace string                 //  
    	Misc       map[string]interface{} // 
    }
    
    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
    "
    , e.Inner, e.Message, e.StackTrace) // } } }

    이런 방식으로 문제를 처리하는 것은 더욱 편리하지만, 여전히 패키지 순환 인용 문제가 있을 수 있다.

    내부 디테일을 숨기는 오류 처리


    상술한 두 가지 방식은 일부 장면에 적응할 수 있지만 순환 의존이 존재할 수 있는 문제를 해결할 수 없다.이를 위해, 우리는 Error()의 가방을 사용하여 문제를 해결하고, 코드 실례를 하나 제시하는데, 아래의 내용은 이 블로그에서 나온 것이다
    그것의 사용은 매우 간단하다. 만약 우리가 오류를 새로 생성하려면 github.com/pkg/errors 함수를 사용해서 오류를 생성하고 창고 정보를 호출할 수 있다.
    func New(message string) error
    

    만약 기존의 New이 있다면, 우리는 그에 대해 재포장 처리를 해야 한다. 이때 세 가지 함수를 선택할 수 있다.
    // 
    func WithMessage(err error, message string) error
    // 
    func WithStack(err error) error
    // 
    func Wrap(err error, message string) error
    

    사실 위의 포장은 자바의 이상 포장과 유사하다. 포장된 것error, 사실은 error이다. 앞의 장에서 잘못된 근본적인 원인을 언급한 것이 바로 이것Cause이다.그래서 이 오류 처리 라이브러리는 우리에게 Cause 함수를 제공하여 우리가 가장 근본적인 오류 원인을 얻을 수 있도록 했다.
    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
    }
    
    Cause 순환을 사용하여 가장 근본(밑바닥)을 찾아낸 것for.

    참고 자료

  • https://ethancai.github.io/2017/12/29/Error-Handling-in-Go/
  • https://www.flysnow.org/2019/01/01/golang-error-handle-suggestion.html
  • https://dave.cheney.net/paste/gocon-spring-2016.pdf
  • 좋은 웹페이지 즐겨찾기