Errors

Errors->에러 #

// Go에선 명시적으로 별도의 반환값을 통해 에러를 전달하는게 일반적이고 관용적입니다.
//  익셉션을 사용하는 Java와 Ruby 그리고 때때로 결괏값과 에러값을 단일값에 오버로딩하는 C와는 대조적입니다.
//  Go의 이런 접근법을 통해 어떤 함수가 에러를 반환했는지를 보고 다른 에러 없는 작업에 사용되는 구조체를 사용하여 쉽게 처리할 수 있습니다.

package main

import "errors"
import "fmt"

// 관용적으로, 에러는 마지막 반환값이며 내장 인터페이스인 `error`를 타입으로 갖습니다.
func f1(arg int) (int, error) {
	if arg == 42 {

		// `errors.New`는 전달된 에러 메시지로 기본적인 `error`값을 생성합니다.
		return -1, errors.New("can't work with 42")

	}

	// 에러 위치의 nil값은 에러가 없다는걸 나타냅니다.
	return arg + 3, nil
}

// `Error()` 메서드를 구현함으로써 커스텀 `error` 타입을 사용하는것도 가능합니다.
//  다음은 인자 에러를 명시적으로 나타내기 위해 커스텀 타입을 사용한 위의 변형된 예제입니다.
type argError struct {
	arg  int
	prob string
}

func (e *argError) Error() string {
	return fmt.Sprintf("%d - %s", e.arg, e.prob)
}

func f2(arg int) (int, error) {
	if arg == 42 {

		// 이 경우 우리는 `&argError` 구문을 사용하여 두 필드 `arg`와 `prob` 값을 가지고 새로운 구조체를 만듭니다.
		return -1, &argError{arg, "can't work with it"}
	}
	return arg + 3, nil
}

func main() {

	// 아래의 두 루프는 에러를 반환하는 각 함수를 테스트합니다.
	// 참고로 `if` 라인에서 한 줄로 에러를 체크하는 방법은 Go의 공통적인 관용적 표현입니다.
	for _, i := range []int{7, 42} {
		if r, e := f1(i); e != nil {
			fmt.Println("f1 failed:", e)
		} else {
			fmt.Println("f1 worked:", r)
		}
	}
	for _, i := range []int{7, 42} {
		if r, e := f2(i); e != nil {
			fmt.Println("f2 failed:", e)
		} else {
			fmt.Println("f2 worked:", r)
		}
	}

	// 커스텀 에러에서 프로그래밍적으로 데이터를 사용하려면, 타입 단언(type assertion)을 통해 커스텀 에러의 인스턴스로 에러값을 받아와야 합니다.
	_, e := f2(42)
	if ae, ok := e.(*argError); ok {
		fmt.Println(ae.arg)
		fmt.Println(ae.prob)
	}
}
$ go run errors.go
f1 worked: 10
f1 failed: can't work with 42
f2 worked: 10
f2 failed: 42 - can't work with it
42
can't work with it

# 에러 핸들링에 대해 더 알고 싶다면 Go 블로그의 [great post](http://blog.golang.org/2011/07/error-handling-and-go.html)를 보세요.