问题描述
我正在玩可追溯的例外。在这个例子中,我尝试对没有加密的东西进行编号。我抓住那个,并试图给出一个适当值的 $ value
变量,然后继续执行:code> try {
my $ m ='Hello';
我的$值;
$ value = + $ m;
put外部值是{$ value。^ name};
CATCH {
当X :: Str :: Numeric {
放$ m不是数字!
放$ m不是数字!;
put内值是{$ value。^ name};
$ value = 0;
put内值现在是$ value。
.resume;
}
default {
put未处理类型{。^ name};
}
}
放块结束;
}
put到底。
CATCH
块可以看到词法范围它在,一个恢复恢复在它离开的地方。我预计我可以改变 $ value
,让其余的块使用该值,但在 CATCH $之外c $ c>该值成为失败:
你好不是数字!
内部值为任何
内部值现在为0
外部值为失败
块结束
结束。
发生什么?
内部尝试
块,使用致命的
生效,导致从方法或子调用立即抛出。在尝试
块的词汇范围之外,请注意: 我的$ value = + $ m;
将导致失败
被分配到 $值
。 尝试
将其更改为:
my $ value =力衰竭(+ $米);
你可以想像如下定义为:
sub force-failure(Mu \f){f.sink if f ~~ Failure; f}
(我手牵手,因为编译器会吐出代码,有一些优化)。
在考虑的情况下, .sink
会引发抛出的异常。 CATCH
块运行。 .resume
表示我们不希望通过 CATCH
块通常发生调用堆栈,因此执行继续执行 force-failure
,然后返回 f
- Failure
。这一切都发生在主线代码分配到 $ value
之前;因此分配失败
,覆盖由 CATCH
块给出的值。
不幸的是,您无法通过 // =
逃脱,因为在运行RHS之前进行测试(这是我们通常希望做的) )。但是,可以这样做:
我的$ numified = + $ m;
我的$值// = $ numified;
当然,这是一个很有创意的例子,因为普通成语将不会有一个尝试
阻止,并将其写为:
我的$ value = + $ m // 0;
从而利用失败
。一般来说,可追溯的例外需要很多的关心,因为在许多情况下,代码不会被期待恢复发生。事实证明,为致命化失败而生成的代码
是这样的一个。
I'm playing with resumable exceptions. In this example, I try to numify something that doesn't numify. I catch that and attempt to give the $value
variable an appropirate value then resume execution:
try {
my $m = 'Hello';
my $value;
$value = +$m;
put "Outside value is 「{$value.^name}」";
CATCH {
when X::Str::Numeric {
put "「$m」 isn't a number!";
put "「$m」 isn't a number!";
put "Inside value is 「{$value.^name}」";
$value = 0;
put "Inside value is now 「$value.」";
.resume;
}
default {
put "Unhandled type 「{.^name}」";
}
}
put "End of the block";
}
put "Got to the end.";
The CATCH
block can see the lexical scope it is in, a resuming picks up where it left off. I expected that I'd be able to change $value
and have the rest of the block use that value, but outside of the CATCH
the value becomes a Failure:
「Hello」 isn't a number!
Inside value is 「Any」
Inside value is now 「0.」
Outside value is 「Failure」
End of the block
Got to the end.
What's up?
Inside of a try
block, use fatal
takes effect, to cause lazy exceptions returned from method or sub calls to throw immediately. Outside the lexical scope of a try
block, note that:
my $value = +$m;
Would result in a Failure
being assigned to $value
. The try
turns it into something more like:
my $value = force-failure(+$m);
Which you could imagine being defined as something like:
sub force-failure(Mu \f) { f.sink if f ~~ Failure; f }
(I'm hand-waving because the compiler spits out the code to do this inline and with a few optimizations).
In the case under consideration, the .sink
triggers the exception to the thrown. The CATCH
block runs. The .resume
indicates that we do not wish to unwind the call stack as would normally happen with a CATCH
block, so execution continues inside of force-failure
, which then returns f
- the Failure
. This all happens prior to the assignment in the mainline code to $value
; the Failure
is therefore assigned, overwriting the value given by the CATCH
block.
Unfortunately, you can't escape this with //=
because that does the test before running the RHS (which is what we usually want it to do). However, it is possible to do:
my $numified = +$m;
my $value //= $numified;
Of course, this is all a bit of a contrived example, since the normal idiom would be to not have a try
block at all, and to write it as:
my $value = +$m // 0;
Thus taking advantage of the Failure
. In general, resumable exceptions need a good amount of care, because in many cases code will not be written expecting a resumption to take place. It turns out that the code generated for fatalizing a Failure
is one such piece.
这篇关于这个Perl 6 CATCH块是否能够在词法范围内改变变量?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!