区分 CATCH 块中的异常和失败 [RAKU]
Distinguish between Exception and Failure in a CATCH block [ RAKU ]
我们知道失败可以由 CATCH 块处理。
在下面的示例中,我们创建了一个 'AdHoc' 失败(在 other-sub 中),我们在 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 块中的 "normal" 异常,以便区分这两种情况?
Failure
和Exception
之间的关系是一个Failure
有一个Exception
——也就是说,它持有异常对象作为其状态的一部分.像这样:
class Failure {
has Exception $.exception;
# ...
}
当 Failure
"explodes" 时,它通过抛出其中的 Exception
来实现。因此,到达 CATCH
块的是 Exception
对象,并且没有 link 返回封闭的 Failure
。 (事实上 ,一个给定的 Exception
对象原则上可以由许多 Failure
持有。)
因此,没有直接的方法可以检测到这一点。从设计的角度来看,您可能不应该,并且应该找到一种不同的方法来解决您的问题。 Failure
只是一种推迟抛出异常并允许将其视为值的方法;这并不意味着潜在问题的性质会发生变化,因为它是作为一个值而不是作为控制流的立即转移来传达的。不幸的是,问题中没有说明最初的目标;您可能会发现查看控制异常很有用,但除此之外可能 post 另一个关于您试图解决的潜在问题的问题。可能有更好的方法。
为了完整起见,我会注意到 有 种间接方法可以检测到 Exception
是由 Failure
抛出的。比如获取异常对象的.backtrace
,查看top frame的包,可以判断出来自Failure
:
sub foo() { fail X::AdHoc.new(message => "foo") }
try {
foo();
CATCH {
note do { no fatal; .backtrace[0].code.package ~~ Failure };
.resume
}
}
但是,这在很大程度上取决于可以轻松更改的实现细节,因此我不会依赖它。
只需删除 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
。 try
做了一些事情,但这里相关的事情是它告诉 Raku 立即将其范围内的任何 Failure
提升为异常——这就是你所说的 don 't想要。所以最简单的解决办法就是停止这样做。
这个答案只是冗长地重复了 jnthn 的部分解释(具体参见他在答案下方写的评论)。但我不相信所有读者都会 spot/understand 这方面的,并且认为对 jnthn 的回答的一两条评论不会有帮助,因此这个答案。
我已将此作为社区答案编写,以确保我不会从任何投票中受益,因为它显然不能保证这一点。如果它获得足够多的反对票,我们就会将其删除。
我们知道失败可以由 CATCH 块处理。
在下面的示例中,我们创建了一个 'AdHoc' 失败(在 other-sub 中),我们在 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 块中的 "normal" 异常,以便区分这两种情况?
Failure
和Exception
之间的关系是一个Failure
有一个Exception
——也就是说,它持有异常对象作为其状态的一部分.像这样:
class Failure {
has Exception $.exception;
# ...
}
当 Failure
"explodes" 时,它通过抛出其中的 Exception
来实现。因此,到达 CATCH
块的是 Exception
对象,并且没有 link 返回封闭的 Failure
。 (事实上 ,一个给定的 Exception
对象原则上可以由许多 Failure
持有。)
因此,没有直接的方法可以检测到这一点。从设计的角度来看,您可能不应该,并且应该找到一种不同的方法来解决您的问题。 Failure
只是一种推迟抛出异常并允许将其视为值的方法;这并不意味着潜在问题的性质会发生变化,因为它是作为一个值而不是作为控制流的立即转移来传达的。不幸的是,问题中没有说明最初的目标;您可能会发现查看控制异常很有用,但除此之外可能 post 另一个关于您试图解决的潜在问题的问题。可能有更好的方法。
为了完整起见,我会注意到 有 种间接方法可以检测到 Exception
是由 Failure
抛出的。比如获取异常对象的.backtrace
,查看top frame的包,可以判断出来自Failure
:
sub foo() { fail X::AdHoc.new(message => "foo") }
try {
foo();
CATCH {
note do { no fatal; .backtrace[0].code.package ~~ Failure };
.resume
}
}
但是,这在很大程度上取决于可以轻松更改的实现细节,因此我不会依赖它。
只需删除 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
。 try
做了一些事情,但这里相关的事情是它告诉 Raku 立即将其范围内的任何 Failure
提升为异常——这就是你所说的 don 't想要。所以最简单的解决办法就是停止这样做。
这个答案只是冗长地重复了 jnthn 的部分解释(具体参见他在答案下方写的评论)。但我不相信所有读者都会 spot/understand 这方面的,并且认为对 jnthn 的回答的一两条评论不会有帮助,因此这个答案。
我已将此作为社区答案编写,以确保我不会从任何投票中受益,因为它显然不能保证这一点。如果它获得足够多的反对票,我们就会将其删除。