루비에서 '예외 => e를 구출하는 것은 왜 나쁜 스타일인가요?
Ryan Davis의 Ruby QuickRef는 (설명 없이) 다음과 같이 말합니다.
예외를 복구하지 않습니다.아니면 찌르겠습니다.
왜 안 되나요?옳은 일은 무엇입니까?
TL;DR: 사용StandardError
일반적인 예외를 포착하기 위해 대신.발생한 원예다예발경우생한시래외 (예: 예도기록복구경는우하하록복구가외를예),복구▁when경▁rescuing), e원래▁isException
아마 괜찮을 겁니다
Exception
루비의 예외 계층 구조의 루트입니다. 그래서 당신이rescue Exception
당신은 다음과 같은 하위 클래스를 포함하여 모든 것에서 구조합니다.SyntaxError
,LoadError
,그리고.Interrupt
.
조구Interrupt
를 사용하여 프로그램을 종료할 수 없습니다.
조구SignalException
프로그램이 신호에 올바르게 응답하지 못하도록 합니다.다음을 제외하고는 죽일 수 없을 것입니다.kill -9
.
조구SyntaxError
는 것을 의미합니다.eval
실패하면 자동으로 수행됩니다.
이 모든 것들은 이 프로그램을 실행하고, 시도하거나, 또는kill
그것:
loop do
begin
sleep 1
eval "djsakru3924r9eiuorwju3498 += 5u84fior8u8t4ruyf8ihiure"
rescue Exception
puts "I refuse to fail or be stopped!"
end
end
에서 구출하기Exception
기본값도 아닙니다.하고있다
begin
# iceberg!
rescue
# lifeboats
end
는 에서구 않습다니지하에서 .Exception
에서 구출합니다.StandardError
다 더 .StandardError
지만구는에서 하는 것.Exception
범위를 좁히는 대신 범위를 넓히고 치명적인 결과를 초래하여 버그 검색을 매우 어렵게 만들 수 있습니다.
만약 당신이 구조하고 싶은 상황이 있다면,StandardError
예외가 있는 변수가 필요합니다. 다음 형식을 사용할 수 있습니다.
begin
# iceberg!
rescue => e
# lifeboats
end
이 값은 다음과 같습니다.
begin
# iceberg!
rescue StandardError => e
# lifeboats
end
몇 안 되는 일반적인 경우 중 하나는 구조하는 것이 제정신인 경우입니다.Exception
는 로깅 이 를 즉시 . " " " "/ " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "
begin
# iceberg?
rescue Exception => e
# do some logging
raise # not enough lifeboats ;)
end
실제 규칙은 다음과 같습니다.예외를 버리지 마세요.당신의 인용문의 저자의 객관성은 의심스럽다, 그것이 그것으로 끝난다는 사실에서 증명됩니다.
아니면 찌르겠습니다.
물론 신호(기본적으로) 예외가 발생하고 일반적으로 장시간 실행되는 프로세스는 신호를 통해 종료되므로 예외를 포착하고 신호 예외를 종료하지 않으면 프로그램을 중지하기가 매우 어렵습니다.그러니 이러지 마:
#! /usr/bin/ruby
while true do
begin
line = STDIN.gets
# heavy processing
rescue Exception => e
puts "caught exception #{e}! ohnoes!"
end
end
아니, 진짜, 하지 마.작동하는지 확인하려고 실행하지도 마.
그러나 스레드 서버가 있고 모든 예외를 원하지 않는다고 가정합니다.
- 무시됨(기본값)
- 합니다. (이 " " "라고 말하면 합니다.
thread.abort_on_exception = true
).
그러면 연결 처리 스레드에서 이를 완벽하게 수용할 수 있습니다.
begin
# do stuff
rescue Exception => e
myLogger.error("uncaught #{e} exception while handling connection: #{e.message}")
myLogger.error("Stack trace: #{backtrace.map {|l| " #{l}\n"}.join}")
end
위의 내용은 Ruby의 기본 예외 처리기의 변형으로 사용할 수 있으며 프로그램을 종료하지 않는다는 장점이 있습니다.레일즈는 요청 처리기에서 이 작업을 수행합니다.
신호 예외는 메인 스레드에서 발생합니다.백그라운드 스레드는 그것들을 얻지 못하므로, 그곳에서 그것들을 잡으려고 노력하는 것은 의미가 없습니다.
이 기능은 문제가 발생할 때마다 프로그램이 단순히 중지되지 않도록 하는 프로덕션 환경에서 특히 유용합니다.그런 다음 로그에 스택 덤프를 저장하고 코드에 추가하여 콜 체인 아래에서 보다 우아한 방식으로 특정 예외를 처리할 수 있습니다.
또한 거의 동일한 효과를 가진 또 다른 루비 관용구가 있다는 것에 주목하십시오.
a = do_something rescue "something else"
줄에서 만약에 이줄면 약에만.do_something
예외를 제기하고, 그것은 루비에 의해 잡히고, 버려집니다.a
됨 됨할"something else"
.
일반적으로 걱정할 필요가 없다는 것을 알고 있는 특별한 경우를 제외하고는 그렇게 하지 마십시오.한 가지 예:
debugger rescue nil
그debugger
함수는 코드에서 중단점을 설정하는 데 꽤 좋은 방법이지만 디버거와 레일즈 외부에서 실행되는 경우 예외가 발생합니다.이제 이론적으로 디버그 코드를 프로그램에 방치해서는 안 됩니다(pff! 아무도 그렇게 하지 않습니다!). 하지만 어떤 이유로 디버거를 계속 실행하지 않고 잠시 동안 디버거를 실행하고 싶을 수도 있습니다.
참고:
신호 예외를 포착하고 무시하는 다른 사용자의 프로그램을 실행한 경우(위 코드 참조):
- Linux의에 리스에, 셸서서, 입력에를 합니다.
pgrep ruby
또는ps | grep ruby
가 되는PID를 , "PID"를 실행합니다.kill -9 <PID>
. - Windows에서 작업 관리자(--)CTRLSHIFTESC를 사용하고 "프로세스" 탭으로 이동하여 프로세스를 찾은 다음 마우스 오른쪽 단추로 클릭하고 "프로세스 종료"를 선택합니다.
- Linux의에 리스에, 셸서서, 입력에를 합니다.
어떤 이유로든 이러한 무시 예외 블록으로 가득 찬 다른 사람의 프로그램으로 작업하는 경우, 이를 메인 라인의 맨 위에 배치하는 것이 한 가지 가능한 cop-out입니다.
%W/INT QUIT TERM/.each { |sig| trap sig,"SYSTEM_DEFAULT" }
이로 인해 프로그램은 정리 없이 예외 처리기를 즉시 종료하고 우회하여 정상 종료 신호에 응답합니다.따라서 데이터 손실이나 이와 유사한 원인이 될 수 있습니다.조심해!
필요한 경우:
begin do_something rescue Exception => e critical_cleanup raise end
실제로 다음을 수행할 수 있습니다.
begin do_something ensure critical_cleanup end
두번째경는우에,는에,
critical cleanup
예외가 발생했는지 여부에 관계없이 매번 호출됩니다.
TL;DR
하지 마rescue Exception => e
(및 예외를 다시 적용하지 않음) - 또는 다리에서 운전할 수 있습니다.
여러분이 차를 타고 있다고 가정해 보겠습니다(Ruby를 실행합니다.에 무선 을 사용하는 새로운 이은 최에무이업장새휠다설니습치했을은링스템시어스티근된착이드선이시스템그레이▁(▁you(▁uses▁system▁with▁wheelwhich다▁a▁the은니▁steering▁installed템습▁upgrade▁recently▁new시최스했치).eval
은 한 것을 .), 하만지당신프머래중구망을쳤는것을몰다다랐니습문이명한로은그▁),다.
당신은 다리 위에 있고, 당신이 난간 쪽으로 조금 가고 있다는 것을 깨닫고, 왼쪽으로 돌면 됩니다.
def turn_left
self.turn left:
end
웁스! 그건 아마 좋지 않을 거야™, 운 좋게도, 루비는.SyntaxError
.
차가 즉시 멈추어야 합니다. 그렇죠?
아니.
begin
#...
eval self.steering_wheel
#...
rescue Exception => e
self.beep
self.log "Caught #{e}.", :warn
self.log "Logged Error - Continuing Process.", :info
end
삐삐삐
경고: 구문 오류 예외가 발생했습니다.
정보: 기록된 오류 - 계속 진행 중입니다.
잘못되었다는 을 알아차리고 휴식 시간을 세게 .^C
:Interrupt
)
삐삐삐
경고: 인터럽트 예외가 발생했습니다.
정보: 기록된 오류 - 계속 진행 중입니다.
네 - 별로 도움이 되지 않았습니다.에서 꽤 .kill
ing:SignalException
).
삐삐삐
경고: 신호 예외 예외가 발생했습니다.
정보: 기록된 오류 - 계속 진행 중입니다.
.kill -9
), 합니다. (시키지 않았기 수 . 의 차 에 있는 그앞) 그리고 당신의 차 뒤에 있는 컴퓨터는 그 앞 좌석으로 돌진합니다.콜라 반 캔이 종이 위로 쏟아집니다.뒤에 있는 식료품들은 으깨져 있고, 대부분 계란 노른자와 우유로 덮여 있습니다.자동차는 심각한 수리와 청소가 필요합니다. (데이터 손실)
보험(백업)이 있기를 바랍니다.아 네 - 에어백이 팽창하지 않았기 때문에, 아마 다쳤을 것입니다(해고 등).
하지만 잠깐!더 많은 이유가 있습니다.rescue Exception => e
!
예를 들어, 당신이 그 차라고 가정하고, 만약 차가 안전 정지 운동량을 초과한다면 에어백이 팽창하는지 확인하려고 합니다.
begin
# do driving stuff
rescue Exception => e
self.airbags.inflate if self.exceeding_safe_stopping_momentum?
raise
end
다음은 이 규칙의 예외입니다.잡으실 수 있습니다Exception
예외를 다시 적용하는 경우에만 가능합니다.그래서, 더 나은 규칙은 절대 삼키지 않는 것입니다.Exception
오류를 항상 다시 확인합니다.
하지만 Ruby와 같은 언어로 구조를 추가하는 것은 모두 잊기 쉬우며, 문제를 다시 제기하기 직전에 구조 성명을 넣는 것은 약간 비건조하게 느껴집니다.그리고 당신은 잊기를 원하지 않습니다.raise
오류를 데 을 빌어요.만약 그렇다면, 그 오류를 찾는 데 행운을 빌어요.
고맙게도, 루비는 굉장해요, 당신은 그냥 그것을 사용할 수 있어요.ensure
키워드: 코드가 실행되는지 확인합니다. 그ensure
키워드는 어떤 경우에도 코드를 실행합니다. 예외가 던져진 경우, 그렇지 않은 경우, 유일한 예외는 세상이 끝나는 경우(또는 다른 예상치 못한 이벤트)입니다.
begin
# do driving stuff
ensure
self.airbags.inflate if self.exceeding_safe_stopping_momentum?
end
쾅! 그리고 그 코드는 어쨌든 실행되어야 합니다.이 사용해야 하는 유일한 는 당이사하유이는유한일입니다.rescue Exception => e
예외에 대한 액세스가 필요한 경우 또는 예외에 대해 코드만 실행하려는 경우입니다.그리고 오류를 다시 제기하는 것을 기억하세요.매번.
참고: @Niall이 지적했듯이 항상 실행되도록 합니다.이는 문제가 발생하더라도 프로그램이 거짓말을 하고 예외를 발생시키지 않을 수 있기 때문에 유용합니다.에어백을 부풀리는 것과 같은 중요한 작업에서는 어떤 일이 있어도 반드시 그렇게 해야 합니다.그렇기 때문에 예외를 두었는지 아닌지, 차가 멈출 때마다 확인하는 것이 좋습니다.에어백을 부풀리는 것은 대부분의 프로그래밍 상황에서 약간의 드문 작업이지만, 이것은 실제로 대부분의 청소 작업에서 매우 일반적입니다.
왜냐하면 이것은 모든 예외를 포착하기 때문입니다.프로그램이 복구될 가능성은 거의 없습니다.
복구 방법을 알고 있는 예외만 처리해야 합니다.특정 유형의 예외가 예상되지 않는 경우 이를 처리하지 않고 큰 소리로 충돌한 다음(로그에 세부 정보 쓰기) 로그를 진단하고 코드를 수정합니다.
예외를 삼키는 것은 좋지 않습니다. 이러지 마십시오.
이는 처리 방법을 모르는 예외를 포착해서는 안 되는 규칙의 특정 사례입니다.처리 방법을 모르는 경우에는 항상 시스템의 다른 부분에서 이를 포착하여 처리하도록 하는 것이 좋습니다.
이 블로그 게시물은 이를 완벽하게 설명합니다.Ruby의 예외 대 표준 오류: 뭐가 달라요?
예외를 복구하면 안 되는 이유
예외 구조의 문제는 실제로 예외에서 상속되는 모든 예외를 복구한다는 것입니다.그 말은... 그들 모두야!
루비에서 내부적으로 사용하는 예외가 있기 때문에 문제가 됩니다.그것들은 당신의 앱과 아무 관련이 없으며, 그것들을 삼키면 나쁜 일이 일어날 것입니다.
다음은 몇 가지 중요한 사항입니다.
신호 예외:인터럽트 - 이를 복구하면 control-c를 눌러 앱을 종료할 수 없습니다.
스크립트 오류:구문 오류 - 구문 오류를 삼키면 puts("Forgot something")와 같은 작업이 자동으로 실패합니다.
메모리 오류 없음 - RAM을 모두 사용한 후 프로그램이 계속 실행되면 어떻게 되는지 알고 싶으십니까?나 역시 그렇지 않다.
begin do_something() rescue Exception => e # Don't do this. This will swallow every single exception. Nothing gets past it. end
이러한 시스템 수준의 예외를 완전히 무시하고 싶지는 않을 것입니다.모든 응용 프로그램 수준 오류만 탐지하려고 합니다.예외로 인해 코드가 발생했습니다.
다행히도, 이것에 대한 쉬운 방법이 있습니다.
대신 표준 오류 복구
주의해야 할 모든 예외는 StandardError에서 상속됩니다.이들은 우리의 오랜 친구들입니다.
NoMethodError - 존재하지 않는 메서드를 호출하려고 할 때 발생합니다.
유형 오류 - 1 + ""와 같은 것으로 인해 발생합니다.
런타임 오류 - 누가 좋은 오래된 런타임 오류를 잊을 수 있습니까?
이러한 오류를 복구하려면 StandardError를 복구해야 합니다.당신은 다음과 같은 것을 작성함으로써 그것을 할 수 있습니다.
begin do_something() rescue StandardError => e # Only your app's exceptions are swallowed. Things like SyntaxErrror are left alone. end
하지만 루비 덕분에 훨씬 더 쉽게 사용할 수 있었습니다.
예외 클래스를 전혀 지정하지 않으면 Ruby는 표준 오류를 의미한다고 가정합니다.따라서 아래 코드는 위 코드와 동일합니다.
begin do_something() rescue => e # This is the same as rescuing StandardError end
언급URL : https://stackoverflow.com/questions/10048173/why-is-it-bad-style-to-rescue-exception-e-in-ruby
'programing' 카테고리의 다른 글
서브셋보다 []이 더 좋은 이유는 무엇입니까? (0) | 2023.06.08 |
---|---|
값 집합 정렬 (0) | 2023.06.08 |
Android:소프트 키보드가 내 보기를 위로 밀어 올리는 것을 방지하려면 어떻게 해야 합니까? (0) | 2023.06.08 |
C에서 데이터 섹션과 bss 섹션의 차이 (0) | 2023.06.08 |
Shiny에서 '최대 업로드 크기 초과' 제한을 변경하고 사용자 파일 입력을 저장하는 방법은 무엇입니까? (0) | 2023.06.08 |