에러처리

최승훈·2020년 8월 15일
0

Golang기초

목록 보기
7/7
post-thumbnail

1. 에러처리의 기본

에러 처리가 필요한 이유

컴파일러가 알아차리지 못하는 프로그램상의 오류를 예방하기 위해서.
반환값이 있는 함수는 논리상 예외(에러)가 있을만한 부분을 에러 처리를 통해 결괏값과 에러 값을 함께 반환해야함.

package main

import "fmt"

func main() {
	var input string
	
        // Scanln은 두 개의 반환값을 가지는데, 첫 번째로는 입력개수, 두번 째는 에러 
	_ , err := fmt.Scanln(&input)

  	// err 가 nil이 아니면 panic(err)구문을 실행해 에러값을 출력하고, panic이 발생함.
	if err != nil {
		panic(err)
	}

	fmt.Println(input)

}

Scanln과 같은 내장표준함수들은 에러 상황과 값을 이미 구현했기 때문에 상황에 따른 에러값을 반환받고 if err != nil {처리구문} 과 같은 조건문으로 에러 값을 출력하고 에러를 핸들링 할 수 있게 되어있음.

개발자가 만든 함수에서 에러 처리

개발자가 만든 함수에서 에러 처리를 할 때는 에러 상황을 직접 정의 하고 에러 값도 직접 지정해야함.

예.

사용자에게 두 실수를 입력받은 후, 나눗셈을 하는 프로그램
나누는 수를 0으로하면 무한대가 되기 때문에 사전에 에러 처리를 하게 만들고 싶음.

에러 처리를 할 때의 두가지 고려
1. 어떤 상황을 에러라고 판단하고 에러 값을 설정할것인가?
2. 어떻게 에러 내용을 출력하고 핸들링 할것인가?

error 타입에 대해
error는 일반적인 타입인 int,float32,string과 같은 타입은 아님.
error는 인터페이스 타입,
error인터페이스는 Error()라는 string형을 반환값으로 갖는 메소드 한개만을 구현하고 있음.

// error인터페이스
type error interface {
  Error() string
}

// errorString 구조체
type errorString sturct {
 	s string 
}

// Error() 메소드의 원형,  errorString의 주소에 직접 접근해서 필드값 s를 반환
func (e *errorString) Error() string {
 	return e.s
}

errorString을 초기화 시키는 방법.
"errors"패키지의 New()함수를 이용

errors.New("ErrorValue")
package main

import (
	"errors"
	"fmt"
)

func divide(a float32, b float32) (result float32, err error) {
	if a == 0 || b == 0 {
		return 0, errors.New("0 으로 나누면 안됭~ㅎ")
	}
	result = a / b
	return
}

func main() {
	var num1 , num2 float32
	fmt.Scanln(&num1 , &num2)

	r , err := divide(num1, num2)

	if err != nil {
		panic(err)
	}

	fmt.Println(r)
}

2. 에러 출력 및 처리

log패키지를 활용한 에러 출력 및 처리

  1. func Fatal(v ...interface{}) : 에러 로그 출력 및 프로그램 종료
  2. func Panic(v ...interface{}) : 시간, 에러 메시지 출력 및 패닉 발생, defer구문이 없을 시 런타임 패틱을 발생시키고 콜스택 출력
  3. func Print(v ...interface{}) : 시간, 에러 메시지를 출력하지만, 프로그램을 종료시키지는 않음.

Print를 활용한 예제

package main

import (
	"fmt"
	"log"
)

func divide(a float32, b float32) (result float32, err error) {
	if b == 0 {
		// 에러 값의 포멧을 지정.
		return 0, fmt.Errorf("%.2f으로 나누지마", b)
	}
	result = a / b
	return
}

func main() {
	var num1 , num2 float32
	fmt.Scanln(&num1 , &num2)

	r , err := divide(num1, num2)

	if err != nil {
      	// log.Print()를 활용해 에러 메시지를 출력하지만,프로그램을 종료하진 않음.
		log.Print(err)
	}

    // 그래서 r의 값의 출력이 됨.
	fmt.Println(r)

}

모든 에러 출력과 처리 방식을 적용한 예

package main

import (
	"fmt"
	"log"
)

// int 형 n 값을 받아 에러를 체크하는 함수
func errorCheck(n int) (string, error) {
	// 매개변수 n 의 값이 1일때만 정상동작으로 처리
	if n == 1 {
		return "show" , nil
	}
	// 매개변수 n 의 값이 1이 아닐때는 에러를 리턴.
	return "", fmt.Errorf("%d의 값은 1이 아닙니다.", n)
}


func main() {
	// errorCheck 의 매개변수로 1을 넘겼기 때문에 정상동작.
	s, err := errorCheck(1)
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println(s)

	// errorCheck 의 매개변수로 2를 넘겼기 때문에 에러 발생.
	s, err = errorCheck(2)
	if err != nil {
		//  log.Print(err)는 에러 메시지만 출력
		log.Print(err)
	}
	fmt.Println(s)

	defer func() {
		fmt.Println("Do defer")
		s, err := errorCheck(4)
		if err != nil {
			log.Fatal(err)
		}
		fmt.Println(s)
	}()

	// errorCheck 의 매개변수로 3를 넘겼기 때문에 에러 발생.
	s, err = errorCheck(3)
	if err != nil {
		// log.Panic(err)이 실행되고 panic이 발생하기 전에 defer 구문
		log.Panic(err)
	}
	fmt.Println(s)
	fmt.Println("Done!!")
}

log.Panic(err)와 log.Fatal(err) 의 차이점.
log.Panic은 런타임 에러를 발생시키고 프로그램을 종료.
log.Fatal은 프로그램을 정상적으로 완전히 종료

log.Panic()과 Panic()함수는 같은 역할.

참조 : https://edu.goorm.io/learn/lecture/2010/%ED%95%9C-%EB%88%88%EC%97%90-%EB%81%9D%EB%82%B4%EB%8A%94-%EA%B3%A0%EB%9E%AD-%EA%B8%B0%EC%B4%88/lesson/385483/%EC%97%90%EB%9F%AC-%EC%B6%9C%EB%A0%A5-%EB%B0%8F-%EC%B2%98%EB%A6%AC

profile
안녕하세요

0개의 댓글