종료하는 panic(), 복구하는 recover()
15 defer와 panic()
종료하는 panic(), 복구하는 recover()

지난 강의에서 함수 내에서 가장 마지막에 꼭 실행하는 defer에 대해서 배웠습니다. defer가 선언된 함수는 중간에 프로그램이 에러가 발생하더라도 꼭 마지막에 실행합니다.(에러가 생기는 코드 전에 선언됐을 때) 이는 "끝내기 전에 이거는 실행하고 끝내줘."라는 것과 같습니다. 하지만 이번 강의에서 배울 panic은 상반된 기능을 합니다. panic은 겉으로 보이게 아무런 문제가 없는데 실행해보니 에러가 발생해서 프로그램을 종료하는 기능을 합니다. 반대로 말하자면 문법 자체를 잘못 입력했을 때 발생하는 에러는 panic이 아닙니다.


여기서 헷갈리는 부분이 있습니다.  "겉으로 보이기에 아무런 문제가 없는데 오류가 발생하는 코드가 무엇이지?" 라고 생각할 수 있습니다. 이것은 바로 '오류'와 '예외'의 차이입니다. 오류는 프로그램상 허용하지 않는 문법과 같은 비정상적인 상황에 발생하는 것을 말합니다. 예를 들어, int형 변수에 30.5를 초기화 하면 오류가 발생합니다. 그리고 예외는 프로그램이 실행되면서 논리상으로 부적합한 상황이 발생하는 것을 말합니다. 예를 들어, 나눗셈을 할 때 10 / 0은 논리적 예외 상황인 것입니다. 따라서 이러한 것들은 프로그램이 오류라고 생각하지 않기 때문에 코드 상에서 따로 예외 처리를 해야합니다.   


아래는 오류가 발생한 경우와 예외 상황에서 panic이 발생한 경우를 순서대로 보여줍니다. 바로 실행해보세요.

실행 언어: go
실행 결과를 확인해보세요!
실행 언어: go
실행 결과를 확인해보세요!

그리고 만약에 panic이 발생한 함수 안에 defer 구문이 있다면 프로그램을 종료하기 전에 defer 구문을 실행하고 종료합니다. 


아래 panic이 발생하고 프로그램이 종료되기 전에  defer 구문이 실행되는 예시 코드가 있습니다. 바로 실행해보세요.

실행 언어: go
실행 결과를 확인해보세요!

반복문 안에서 선언한 배열의 개수보다 큰 인덱스 값을 접근함으로써 panic이 발생하고 프로그램이 종료됩니다. 하지만 defer fmt.Println("Panic done") 구문이 panic 에러가 발생하는 코드 전에 선언되었기 때문에 프로그램이 종료되기 전에 "Panic done"이 출력되고 종료됩니다. 따라서 main() 함수에 있는 fmt.Println("Hello, world!")는 실행되지 않습니다.(panic이 발생해 프로그램이 종료돼서)


또한, panic은 에러뿐만 아니라 사용자가 panic() 함수를 이용해 예외 상황일때(아무때나 사용할 수 있지만) 직접 panic 에러를 발생시킬수 있습니다. 여기서 panic() 함수 안에 에러 메시지를 사용자 설정으로 출력할 수 있습니다. 조건문 강의에서 사용했던 예시 코드를 활용해보겠습니다.


아래 코드를 바로 실행해보세요.

실행 언어: go
실행 결과를 확인해보세요!

이렇게 panic() 함수는 프로그램 흐름에서 에러로 처리하고 싶은 부분에 개발자의 설정으로 사용할 수 있습니다. 

위 코드는 범위에 벗어난 숫자를 입력했을 때 panic() 함수를 호출해 에러를 발생시켜 프로그램을 종료합니다. 예시는 예시일 뿐, 숫자를 잘못 입력했다고 프로그램을 종료시키도록 프로그램을 제작하는 개발자는 없을 것이라고 생각합니다. 


panic을 막는 recover() 함수


위 예시에서 언급했듯이 에러가 생기는 상황에 바로 panic을 발생시키고 프로그램을 종료하는 것은 안 좋은 방법이 될 수 있습니다. 그렇다면 에러가 생기는 상황만 예외 처리를 하면 어떨까요? Java에서는 try ~catch 구문을 사용해 이러한 예외 처리를 하는데 recover() 함수도 이와 같은 역할을 한다고 생각하면 됩니다. panic 상황이 생겼을 때 프로그램을 종료하지 않고 예외 처리를 하는 것입니다. panic() 함수와 recover() 함수를 사용해  프로그램 흐름을 사용자가 미리 예외처리를 할 수 있는데 위에서 언급한 것처럼 panic 상황에서 프로그램이 종료되지 않고 어떤 구문을 실행시키려면 defer 구문을 사용해야합니다. 따라서 예외 처리를 하기 위해서는 recover() 함수와 defer 구문을 항상 같이 사용해야합니다.


아래 위에서 살펴본  index out of range에러를 발생하는 코드를 recover() 함수를 사용해 예외 처리를 한 예시 코드가 있습니다.

실행 언어: go
실행 결과를 확인해보세요!

위 코드에서 제일 눈에 띄는 것은 panic이 발생하는 코드 전에 defer 구문을 사용한 익명 함수로 recover() 함수를 선언해놓은 것입니다. 따라서 for문에서 index out of range panic이 발생해 프로그램이 종료 되기 전에 지연 처리한 defer 익명 함수가 호출되고 익명 함수 내에 recover() 함수가 호출되면서 panic을 복구합니다. 따라서 프로그램이 그냥 종료되지 않고 main() 함수에서 선언한 fmt.Println("Hello, world!")가 호출되어 프로그램이 종료되지 않았다는 것을 증명합니다. panic이 발생한 해당 함수는 종료되고 다음 코드를 실행합니다. 그래서 panicTest() 다음 코드인 fmt.Println("Hello, world!")을 실행한 것입니다.


쉽게 말해 recover() 함수는

  • panic이 발생해 프로그램이 종료되는 것을 막고 복구합니다.
  • 프로그램이 종료되기 전에 실행되어야 함으로 defer 가 선언된 함수 안에서 쓰입니다.
  • 에러 메시지를 반환합니다. 따라서 변수에 초기화해서 에러 메시지를 출력할 수 있습니다. 변수에 초기화하지 않으면 따로 에러 메시지를 출력하지 않습니다. 

아래는 중간고사 평균 점수2 실습에 도움이 될만한 예시 코드입니다. 재귀 함수를 이용해 defer 구문에 복구와 동시에 main() 함수를 다시 실행시킵니다.

실행 언어: go
실행 결과를 확인해보세요!
질문하기
추가 자료
no files uploaded

추가 자료가 없습니다

여기서 새로운 학습 자료를 확인하세요!
선생님이 추가한 자료들을 바로 확인할 수 있어요.