当前位置: 首页 > 知识库问答 >
问题:

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

寿卜鹰
2023-03-14

我在玩可恢复的例外。在本例中,我尝试numify一些不numify的东西。我捕捉到这一点,并尝试为$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之外,该值变为失败:

「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.

搞什么?

共有1个答案

伯英锐
2023-03-14

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

my $value = +$m;

将导致故障分配给$valuetry将其转换为类似于:

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

你可以想象它被定义为这样的东西:

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

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

在所考虑的情况下,。sink触发引发的异常。CATCH块运行。。resume表示我们不希望像通常在CATCH块中那样释放调用堆栈,因此在强制失败内部继续执行,然后返回f-失败。这一切都发生在主线代码中分配给$value之前;因此分配了故障,覆盖了CATCH块给出的值。

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

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

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

my $value = +$m // 0;

从而利用了Failure。一般来说,可恢复的异常需要非常小心,因为在许多情况下,代码不会期望发生恢复。事实证明,为使Failure失效而生成的代码就是这样一段代码。

 类似资料:
  • 问题内容: 这将编译 这不会 我希望两者都能编译(也许这是C的工作方式?)。是什么原因导致无法在外部块中以相同的名称声明一个块中的变量? 问题答案: 简短的答案是:因为这是JLS§6.4中定义Java语言的方式。 您可能从其他语言中使用过,因此允许使用所谓的可变阴影。但是,Java语言的发明者认为这是一个笨拙的功能,他们不希望使用其语言: 此限制有助于检测其他一些非常模糊的错误。 但是,正如作者在

  • 问题内容: 我知道变量作用域由块的开始和块的结尾包围。如果在块内声明了相同的变量,则会发生编译错误。但是,请看以下示例。 在这里,可以在方法中重新声明,尽管它已经在类中声明了。但是在块中,无法重新声明。 为什么类范围变量的重新声明不产生错误,而方法范围变量的重新声明却产生错误? 问题答案: 这是因为不是变量,而是实例字段。允许局部变量与字段具有相同的名称。为了区分变量和具有相同名称的字段,我们在实

  • 问题内容: 我知道变量作用域由块的开始和块的结尾包围。如果在块内声明了相同的变量,则会发生编译错误。但是,请看以下示例。 在这里,可以在方法中重新声明,尽管它已经在类中声明了。但是在块中,无法重新声明。 为什么类范围变量的重新声明不产生错误,而方法范围变量的重新声明却产生错误? 问题答案: 这是因为不是变量,而是实例字段。允许局部变量与字段具有相同的名称。为了区分变量和具有相同名称的字段,我们在实

  • 问题内容: 尽管在ChildCtrl中实例化了一个“新”变量,我如何进行变量更改并将其轻松传播回ParentCtrl?加分点数最少,甚至没有$ on和$ watch(使其更易于实现) ParentCtrl ChildCtrl / ChildCtrl2 / ChildCtrl3 / ChildCtrl4 视图 我的ChildCtrl的区别就足够大了,我无法轻松抽象出主布局和ng-view,但是它们都

  • 本章介绍当模板在访问变量时发生了什么事情,还有变量是如何存储的。 当调用 Template.process 方法时,它会在方法内部创建一个 Environment 对象,在 process 返回之前一直使用。 该对象存储模板执行时的运行状态信息。除了这些,它还存储由模板中指令,如 assign, macro, local 或 global 创建的变量。 它不会尝试修改传递给 process 的数据

  • 问题内容: 我有两个控制器,一个封装在另一个中。现在,我知道子范围从父范围继承属性,但是有没有办法更新父范围变量?到目前为止,我还没有遇到任何明显的解决方案。 在我的情况下,我在表单中有一个日历控制器。我想从父范围(即表单)更新开始日期和结束日期,以便表单在提交时具有开始日期和结束日期。 问题答案: 您需要在父作用域中使用一个对象(不是原始对象),然后就可以直接从子作用域中更新它 上级: ctrl