这个Perl 6 CATCH块是否能够更改词法范围内的变量?

bri*_*foy 3 exception perl6

我正在玩可恢复的例外.在这个例子中,我尝试编号不编号的东西.我抓住了它并尝试给$value变量一个合适的值然后恢复执行:

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

CATCH块可以看到它所处的词法范围,一个恢复从它停止的地方开始.我希望我能够更改$value并让其余的块使用该值,但在CATCH该值之外变为失败:

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

这是怎么回事?

Jon*_*ton 5

try块内部use fatal生效,导致从方法或子调用返回的延迟异常立即抛出.在try块的词法范围之外,请注意:

my $value = +$m;
Run Code Online (Sandbox Code Playgroud)

会导致Failure被分配到$value.将try它变成更多的东西一样:

my $value = force-failure(+$m);
Run Code Online (Sandbox Code Playgroud)

你可以想象被定义为:

sub force-failure(Mu \f) { f.sink if f ~~ Failure; f }
Run Code Online (Sandbox Code Playgroud)

(我正在挥手,因为编译器吐出代码来内联并进行一些优化).

在考虑的情况下,.sink触发抛出的异常.该CATCH块运行.这.resume表明我们不希望像CATCH块通常发生的那样解开调用堆栈,因此内部继续执行force-failure,然后返回f- Failure.这一切都发生在主线代码中的赋值之前$value; 将Failure因此被认为是,覆盖由给定的值CATCH的块.

不幸的是,你无法逃避这一点,//=因为它在运行RHS之前进行了测试(这是我们通常希望它做的).但是,有可能做到:

my $numified = +$m;
my $value //= $numified;
Run Code Online (Sandbox Code Playgroud)

当然,这只是一个人为的例子,因为正常的习惯用法是根本没有try块,并把它写成:

my $value = +$m // 0;
Run Code Online (Sandbox Code Playgroud)

因此利用了Failure.通常,可恢复的异常需要大量的注意,因为在许多情况下,代码将不会被写入,期望恢复发生.事实证明,为致命a Failure而生成的代码就是这样一个.

  • 希望当有人发现文档缺乏或不清楚时,那个人会在https://github.com/perl6/doc上创建一个问题,所以至少会看到这个问题并且不会出现问题. (2认同)