21. 에러 핸들링
21. 에러 핸들링
✅ 1. 에러 반환
- 에러를 처리하는 가장 기본 방식은 에러를 반환하고 알맞게 처리하는 방식이다
1 2 3 4
if err != nil { fmt.Println("파일 생성에 실패했습니다.", err) return }
1.1 사용자 에러 반환
1
2
3
4
5
6
7
8
9
10
11
12
13
package main
import (
"fmt"
"math"
)
func Sqrt(f float64) (float64, error) {
if f < 0 {
return 0, fmt.Errorf("제곱근은 양수여야 합니다. f:%g", f)
}
return math.Sqrt(f), nil
}
fmt
패키지의Errorf()
함수를 이용하면 원하는 에러 메시지를 만들 수 있다errors
패키지의New()
함수를 이용해서 error를 생성할 수도 있다1 2 3
import "errors" errors.New("에러 메시지")
✅ 2. 에러 타입
- 사실 error는 인터페이스로, 문자열을 반환하는
Error()
메서드로 구성되어 있다.1 2 3
type error interface { Error() string }
- 즉, 어떤 타입이든
Error() string
메서드를 포함한다면 에러로 사용할 수 있다.2.1 에러 랩핑
fmt.Errorf()
함수와%w
서식으로 에러를 감쌀 수 있다errors.As()
함수를 사용하면 에러 체인을 따라서 변환 가능한 에러를 찾으며, 변환 가능한 에러가 있다면 값을 넣고 true를 반환한다
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
package main
import (
"errors"
"fmt"
"strconv"
)
func Example() error {
val := "test"
if _, err := strconv.Atoi(val); err != nil {
return fmt.Errorf("parse error=%q: %w", val, err)
}
return nil
}
func main() {
err := Example()
if err != nil {
fmt.Printf("%T\n", err) // *fmt.wrapError
var numsErr *strconv.NumError
if errors.As(err, &numsErr) {
fmt.Println("Func:", numsErr.Func, "Num:", numsErr.Num, "Cause:", numsErr.Err) // Func: Atoi Num: test Cause: invalid syntax
return
}
}
}
✅ 3. 패닉
- 패닉(panic)은 프로그램을 정상 진행시키기 어려운 경우, 프로그램 흐름을 중지시키는 기능이다
- Go 언어에서는 내장 함수
panic()
으로 패닉 기능을 제공한다
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
package main
import "fmt"
func main() {
divide(9, 0) // panic: b cannot be zero
}
func divide(a, b int) {
if b == 0 {
panic("b cannot be zero")
}
fmt.Printf("%v / %v = %v", a, b, a/b)
}
panic()
을 호출하고 인수로 에러 메시지를 입력하면 프로그램을 즉시 종료하고 에러 메시지를 출력하고 콜 스택을 표시한다
3.1 패닉 생성
1
func panic(interface{})
- 어떤 타입이든 인자로 가능하나, 일반적으로는 string 타입 메시지나
fmt.Errorf()
를 통해 만든 에러 타입을 주로 인수로 넣어준다
3.2 패닉 전파 및 복구
- panic은 호출 순서를 거슬러 올라가며 전파되며,
main()
함수에서까지 복구되지 않으면 프로그램이 강제종료된다 recover()
함수를 호출해 패닉 복구를 할 수 있다recover()
함수가 호출되는 시점에 패닉이 전파 중이면 panic 객체를 반환하고 아니면 nil을 반환한다
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
package main
import "fmt"
func main() {
f()
fmt.Println("프로그램 계쏙 실행")
}
func f() {
fmt.Println("f() 실행")
defer func() {
if r := recover(); r != nil {
fmt.Println("패닉 복구 - ", r)
}
}()
g()
}
func g() {
panic("패닉 테스트")
}
// f() 실행
// 패닉 복구 - 패닉 테스트
// 프로그램 계쏙 실행
3.3 recover() 결과
1
func recover() interface{}
recover()
로 반환한 타입을 실제로 사용하려면 Type assertion으로 검사해야한다
1
2
3
if r, ok := recover().(net.Error); ok {
fmt.Println("r is net Error Type")
}
This post is licensed under CC BY 4.0 by the author.