区分 CATCH 块中的异常和失败 [RAKU]

jak*_*kar 9 exception try-catch raku

我们知道故障可以由 CATCH 块处理。

在下面的示例中,我们创建了一个“AdHoc”失败(在其他子中),并在一个 CATCH 块中(在我的子中)处理异常

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();
Run Code Online (Sandbox Code Playgroud)

输出如下:

AdHoc Exception handled here
This was a Failure
Run Code Online (Sandbox Code Playgroud)

我的问题是:我们如何区分 CATCH 块中的失败和“正常”异常以区分这两种情况?

Jon*_*ton 12

Failure和之间的关系Exception是 aFailure有一个Exception- 也就是说,它将异常对象作为其状态的一部分。像这样的东西:

class Failure {
    has Exception $.exception;
    # ...
}
Run Code Online (Sandbox Code Playgroud)

当一个Failure“爆炸”时,它会通过抛出Exception里面的那个来实现。因此,到达CATCH块的是Exception对象,并且没有返回到封闭Failure. (事实上​​,一个给定的Exception对象原则上可以被许多Failures持有。)

因此,没有直接的方法可以检测到这一点。从设计的角度来看,您可能不应该这样做,而应该找到一种不同的方法来解决您的问题。AFailure只是一种推迟抛出异常并允许将其视为值的方法;根本问题的性质并不打算改变,因为它是作为一个值而不是作为控制流的立即转移来传达的。不幸的是,问题中没有说明最初的目标;您可能会发现查看控件异常很有用,但除此之外,您可能会发布另一个关于您试图解决的潜在问题的问题。可能有更好的方法。

为了完整起见,我会注意到有一些间接的方法可以检测到Exception是由Failure. 例如,如果您获取.backtrace异常对象的 并查看顶部框架的包,则可以确定它来自于Failure

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

但是,这在很大程度上取决于可以轻松更改的实现细节,因此我不会依赖它。


rai*_*iph 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();
Run Code Online (Sandbox Code Playgroud)

你用过try。Atry做了一些事情,但这里的相关事情是它告诉 Raku 立即将Failure其范围内的任何s提升为异常——这就是你所说的你想要的。所以最简单的解决方案就是停止这样做。


这个答案只是冗长地重复了 jnthn 的部分解释(特别参见他在答案下面写的评论)。但我不相信所有读者都会发现/理解这方面,并且不认为对 jnthn 的回答发表一两条评论会有所帮助,因此这个答案。

我将其写为社区答案,以确保我不会从任何赞成票中受益,因为这显然无法保证。如果它获得足够的反对票,我们将删除它。