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

Should this Perl 6 CATCH block be able to change variables in the lexical scope?

我正在玩可恢复的异常。在此示例中,我尝试对不进行数字化的内容进行数字化。我抓住了它并尝试给 $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.";

CATCH 块可以看到它所在的词法作用域,从中断处继续。我希望我能够更改 $value 并让块的其余部分使用该值,但在 CATCH 之外,该值变为 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.

怎么了?

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

my $value = +$m;

将导致 Failure 被分配给 $valuetry 将它变成更像的东西:

my $value = force-failure(+$m);

您可以将其定义为:

sub force-failure(Mu \f) { f.sink if f ~~ Failure; f }

(我在挥手,因为编译器吐出代码来内联执行此操作并进行了一些优化)。

在考虑的情况下,.sink触发了抛出的异常。 CATCH 块运行。 .resume 表示我们不希望像 CATCH 块通常发生的那样展开调用堆栈,因此执行在 force-failure 内部继续,然后 returns f - Failure。这一切都发生在主线代码赋值给 $value 之前; Failure 因此被分配,覆盖 CATCH 块给出的值。

不幸的是,您不能使用 //= 来逃避它,因为它会在 运行 RHS 之前进行测试(这是我们通常希望它做的)。但是,可以这样做:

my $numified = +$m;
my $value //= $numified;

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

my $value = +$m // 0;

于是趁势Failure。通常,可恢复异常需要格外小心,因为在许多情况下,不会编写期望恢复发生的代码。事实证明,为使 Failure 致命而生成的代码就是其中之一。