CATCH 블록에서 예외와 실패 구분 [RAKU]


9

CATCH 블록이 실패를 처리 할 수 ​​있다는 것을 알고 있습니다.

다음 예에서는 'AdHoc'실패 (다른 서브)를 작성하고 CATCH 블록 (예 : my-sub)의 예외를 처리합니다.

sub my-sub {
    try {
        CATCH {
            when X::AdHoc { say 'AdHoc Exception handled here'; .resume }
            default {say 'Other Exception'; .resume}
        }

        my $b = other-sub();

        $b.so ?? $b.say !! 'This was a Failure'.say;
    }
}

sub other-sub { fail 'Failure_X' }

my-sub();

출력은 다음과 같습니다.

AdHoc Exception handled here
This was a Failure

내 질문은 : 두 경우를 구별하기 위해 CATCH 블록에서 실패와 "정상"예외를 어떻게 구분할 수 있습니까?

답변:


12

관계 FailureExceptionA는 점이다 Failure갖는다 Exception- 말 즉, 그 상태의 일부를 제외하고 개체를 보유하고있다. 이 같은:

class Failure {
    has Exception $.exception;
    # ...
}

Failure"폭발"이,이 던져서 그렇게 않는 Exception그것의 내부입니다. 따라서 CATCH블록에 도달하는 것은 Exception객체이며 엔 클로징에 대한 링크는 없습니다 Failure. (사실 주어진 Exception객체는 원칙적으로 많은 사람들이 보유 할 수 있습니다 Failure.)

따라서이를 감지하는 직접적인 방법은 없습니다. 디자인 관점에서 볼 때 아마도 문제가되지 않아야하며 문제를 해결할 다른 방법을 찾아야합니다. A Failure는 예외 던지기를 연기하고 예외를 가치로 취급 할 수있게하는 방법 일뿐입니다. 제어 흐름의 즉각적인 전송이 아닌 가치로 전달되기 때문에 근본적인 문제의 본질이 변경되는 것은 아닙니다. 불행히도, 원래 목표는 질문에 명시되지 않았습니다. 제어 예외를 살펴 보는 것이 유용 할 수도 있지만 해결하려는 근본적인 문제에 대한 다른 질문을 게시 할 수도 있습니다. 아마도 더 좋은 방법이있을 것입니다.

완성도를 위해, 나는 거기에 있습니다 것 입니다 하나는이 있음을 감지 할 수 있다는 간접적 인 방법 Exceptiona로 던져졌다가 Failure. 예를 들어 .backtrace예외 객체를 가져 와서 최상위 프레임의 패키지를 보면 다음에서 비롯된 것인지 확인할 수 있습니다 Failure.

sub foo() { fail X::AdHoc.new(message => "foo") }
try {
    foo();
    CATCH {
        note do { no fatal; .backtrace[0].code.package ~~ Failure };
        .resume
    }
}

그러나 이것은 쉽게 변경할 수있는 구현 세부 사항에 크게 의존하므로 이에 의존하지 않습니다.


일을 명확히하기 위해, 내 의도는 CATCH 블록에서 예외에 대해서만 처리하는 것입니다. 실패의 경우 아무 일도없는 것처럼 재개하고 나머지 코드 (CATCH 외부)가 실패를 처리하게하십시오. 내 예에서는 반환 된 실패가 포함 된 예외를 트리거하지 않을 것으로 예상했습니다! 내가 한 것은 $ b의 결과를 얻고 Bool로 확인하는 것입니다. 내 견해로는 실패의 "사용"을 구성하지 않으므로 CATCH 블록을 트리거하지 않습니다! 그 대신 CATCH가 항상 실패에 포함 된 예외를 처리하는 것 같습니다 !!
카르

또한 귀하의 예에서 실패를 감지하는 간접적 인 방법에 대해 반환 된 Bool (실패 유형의 스마트 검사에서)은 "False"값입니다. 그러나 나는 그것이 "참"일 것으로 예상했다! 내가 뭘 놓 쳤니???
카르

1
@jakar try블록은 use fatalpragma를 의미하는데 , 이는 블록 Failure에서 이루어진 호출에서 반환 된 모든 것이 즉시 예외로 변환 됨을 의미합니다 . 그냥 사용하지 마십시오 try; a CATCH는 Raku의 모든 블록에 들어갈 수 있습니다 (따라서 레벨에 맞추십시오 sub). 또는 블록 no fatal상단에 쓰 십시오 try.
조나단 워싱턴

그리고 두 번째 코멘트는 어떻습니까?
카르

1
예제를 실행하면 True로컬에있는 Rakudo 버전으로 인쇄 했습니다. 그것이 당신에게 있지 않다면, 이것은 이것의 취약성에 대한 요점을 증명합니다.
조나단 워싱턴

6

try래퍼를 제거하십시오 .

sub my-sub {

#    try {              <--- remove this line...

        CATCH {
            when X::AdHoc { say 'AdHoc Exception handled here'; .resume }
            default {say 'Other Exception'; .resume}
        }

        my $b = other-sub();

        $b.so ?? $b.say !! 'This was a Failure'.say;

#    }                  <--- ...and this one

}

sub other-sub { fail 'Failure_X' }

my-sub();

사용했습니다 try. A try는 몇 가지 일을하지만 여기서 적절한 것은 Raku가 Failure범위에서 s를 예외 로 즉시 홍보하도록 지시한다는 것입니다. 이는 원하지 않는 것 입니다. 따라서 가장 간단한 해결책은 그 일을 중단하는 것입니다.


이 답변은 jnthn의 설명 중 일부를 장황하게 반복합니다 (특히 그의 답변 아래에 쓴 주석 참조). 그러나 나는 모든 독자 들이이 측면을 발견 / 이해할 것이라고 확신하지 못했으며 jnthn의 답변에 대한 의견이 도움이 될 것이라고 생각하지 않았 으므로이 답변입니다.

나는 이것을 확실하게 보증하지 않기 때문에 공감대로부터 이익을 얻지 못하도록 커뮤니티 답변으로 이것을 작성했습니다. 다운 보트가 충분하면 삭제합니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.