수색…


소개

Go에서는 예기치 않은 상황이 예외가 아닌 오류를 사용하여 처리됩니다. 이 방법은 try / catch 블록을 사용하여 Java 나 다른 객체 지향 언어보다 errno를 사용하는 C의 방법과 더 비슷합니다. 그러나 오류는 정수가 아니라 인터페이스입니다.

일반적으로 실패 할 수있는 함수는 마지막 반환 값으로 오류 를 반환합니다. 이 오류가 nil이 아닌 경우, 문제가 발생했습니다 함수의 호출자는 그에 따라 조치를 취해야합니다.

비고

이동에 오류를 발생시키지 않는 방법합니다. 대신 오류가 발생하면 오류를 반환 합니다.

함수가 실패 할 수있는 경우 마지막으로 반환 된 값은 일반적으로 error 유형입니다.

// This method doesn't fail
func DoSomethingSafe() {
}

// This method can fail
func DoSomething() (error) {
}

// This method can fail and, when it succeeds,
// it returns a string.
func DoAndReturnSomething() (string, error) {
}

오류 값 만들기

오류를 만드는 가장 간단한 방법은 errors 패키지를 사용하는 것입니다.

errors.New("this is an error")

오류에 추가 정보를 추가하려는 경우 fmt 패키지는 유용한 오류 생성 방법도 제공합니다.

var f float64
fmt.Errorf("error with some additional information: %g", f)

다음은 함수에서 오류가 반환 된 전체 예제입니다.

package main

import (
    "errors"
    "fmt"
)

var ErrThreeNotFound = errors.New("error 3 is not found")

func main() {
    fmt.Println(DoSomething(1)) // succeeds! returns nil
    fmt.Println(DoSomething(2)) // returns a specific error message
    fmt.Println(DoSomething(3)) // returns an error variable
    fmt.Println(DoSomething(4)) // returns a simple error message
}

func DoSomething(someID int) error {
    switch someID {
    case 3:
        return ErrThreeNotFound
    case 2:
        return fmt.Errorf("this is an error with extra info: %d", someID)
    case 1:
        return nil
    }

    return errors.New("this is an error")
}

놀이터에서 열기

사용자 정의 오류 유형 작성

Go에서 오류는 자체를 문자열로 설명 할 수있는 모든 값으로 나타냅니다. 내장 error 인터페이스를 구현하는 모든 유형은 오류입니다.

// The error interface is represented by a single
// Error() method, that returns a string representation of the error
type error interface {
    Error() string
}

다음 예제에서는 문자열 복합 리터럴을 사용하여 새 오류 유형을 정의하는 방법을 보여줍니다.

// Define AuthorizationError as composite literal
type AuthorizationError string

// Implement the error interface
// In this case, I simply return the underlying string
func (e AuthorizationError) Error() string {
    return string(e)
}

내 사용자 정의 오류 유형을 오류로 사용할 수 있습니다.

package main

import (
    "fmt"
)

// Define AuthorizationError as composite literal
type AuthorizationError string

// Implement the error interface
// In this case, I simply return the underlying string
func (e AuthorizationError) Error() string {
    return string(e)
}

func main() {
    fmt.Println(DoSomething(1)) // succeeds! returns nil
    fmt.Println(DoSomething(2)) // returns an error message
}

func DoSomething(someID int) error {
    if someID != 1 {
        return AuthorizationError("Action not allowed!")
    }

    // do something here

    // return a nil error if the execution succeeded
    return nil
}

오류 반환

이동에서 오류가 발생하지 않습니다. 대신 error 하면 error반환 합니다.

// This method can fail
func DoSomething() error {
    // functionThatReportsOK is a side-effecting function that reports its
    // state as a boolean. NOTE: this is not a good practice, so this example
    // turns the boolean value into an error. Normally, you'd rewrite this
    // function if it is under your control.
    if ok := functionThatReportsOK(); !ok {
        return errors.New("functionThatReportsSuccess returned a non-ok state")
    }

    // The method succeeded. You still have to return an error
    // to properly obey to the method signature.
    // But in this case you return a nil error.
    return nil
}

메서드가 여러 값을 반환하고 실행이 실패 할 수있는 경우 표준 규칙은 마지막 인수로 오류를 반환하는 것입니다.

// This method can fail and, when it succeeds,
// it returns a string.
func DoAndReturnSomething() (string, error) {
    if os.Getenv("ERROR") == "1" {
        return "", errors.New("The method failed")
    }

    s := "Success!"

    // The method succeeded.
    return s, nil
}

result, err := DoAndReturnSomething()
if err != nil {
    panic(err)
}

오류 처리

Go에서는 함수 호출에서 오류를 반환 할 수 있습니다. 관례는 메서드가 실패 할 경우 마지막으로 반환 된 인수가 error 입니다.

func DoAndReturnSomething() (string, error) {
    if os.Getenv("ERROR") == "1" {
        return "", errors.New("The method failed")
    }

    // The method succeeded.
    return "Success!", nil
}

메서드가 실패했는지 확인하기 위해 여러 변수 할당을 사용합니다.

result, err := DoAndReturnSomething()
if err != nil {
    panic(err)
}

// This is executed only if the method didn't return an error
fmt.Println(result)

오류에 관심이 없으면 _ 에 할당하여 무시할 수 있습니다.

result, _ := DoAndReturnSomething()
fmt.Println(result)

물론 오류를 무시하면 심각한 영향을 미칠 수 있습니다. 따라서 일반적으로 권장되지 않습니다.

여러 메서드 호출이 있고 체인의 하나 이상의 메서드가 오류를 반환 할 수있는 경우 오류를 처리 할 수있는 첫 번째 수준으로 오류를 전파해야합니다.

func Foo() error {
    return errors.New("I failed!")    
}

func Bar() (string, error) {
    err := Foo()
    if err != nil {
        return "", err
    }

    return "I succeeded", nil
}

func Baz() (string, string, error) {
    res, err := Bar()
    if err != nil {
        return "", "", err
    }

    return "Foo", "Bar", nil
}

공황에서 회복하기

일반적인 실수는 슬라이스를 선언하고 슬라이스를 초기화하지 않고 슬라이스에서 인덱스를 요청하기 시작하면 "범위를 벗어난 인덱스"패닉이 발생합니다. 다음 코드는 프로그램을 종료하지 않고 패닉 상태에서 복구하는 방법을 설명합니다. 이는 패닉에 대한 정상적인 동작입니다. 대부분의 경우, 패닉 상태에서 프로그램을 종료하는 대신 오류를 반환하는 것은 개발 또는 테스트 목적으로 만 유용합니다.

type Foo struct {
    Is []int
}

func main() {
    fp := &Foo{}
    if err := fp.Panic(); err != nil {
        fmt.Printf("Error: %v", err)
    } 
    fmt.Println("ok")
}

func (fp *Foo) Panic() (err error) {
    defer PanicRecovery(&err)
    fp.Is[0] = 5
    return nil
}

func PanicRecovery(err *error) {

    if r := recover(); r != nil {
        if _, ok := r.(runtime.Error); ok {
             //fmt.Println("Panicing")
             //panic(r)
             *err = r.(error) 
        } else {
            *err = r.(error)
        }
    }
}

클로저가 아닌 별도의 함수를 사용하면 공황이 발생하기 쉬운 다른 함수에서 동일한 함수를 재사용 할 수 있습니다.



Modified text is an extract of the original Stack Overflow Documentation
아래 라이선스 CC BY-SA 3.0
와 제휴하지 않음 Stack Overflow