9

从不是例程的块中从 CATCH 移相器返回值的语法是什么?

sub foo() {
    <1 2 3>.map: -> $a {
        die 'oops';
        CATCH { default { 'foo' } }
    }
}

sub bar() {
    <1 2 3>.map: -> $a {
        die 'oops';
        CATCH { default { return 'bar' } }
    }
}

say foo(); # (Nil, Nil, Nil)
say bar(); # Attempt to return outside of immediatelly-enclosing Routine (i.e. `return` execution is outside the dynamic scope of the Routine where `return` was used)

编辑:所需的输出是:

say baz(); # (baz baz baz)

用例是使用间歇mapSeq抛出异常的方法,通过返回默认值来处理传递给 map 的块内的异常。

4

2 回答 2

8

Return 退出函数范围,但是您在其中使用它的方式bar()有两个函数在起作用。

  1. bar()方法本身。
  2. 您将返回值嵌入其中的 lambda。

这意味着您的返回是模棱两可的(嗯,至少对某些人来说)并且编译器会犹豫。

如果没有“返回”,则 in 中的值foo()将作为块内的常量处理,并且该块返回 Nil。这意味着在foo()你有效地避免了解析 的含义return,有效地将 a 压Nil入堆栈。

这就是为什么您Nil在捕获的输出中有 3 秒的foo(). 因为bar()不清楚您是否希望bar()在第一次抛出异常时终止例程的执行,或者您是否只想将 CATCH 块推入堆栈'bar'的非值传回。Nil

您的代码稍作修改的版本

#!/bin/env perl6

sub foo() {
    <1 2 3>.map: -> $a {
        die 'oops';
    }
    CATCH { default { 'foo' } }
}

sub bar() {
    <1 2 3>.map: -> $a {
        die 'oops';
    }
    CATCH { default { return 'bar' } }
}

say foo();

say bar();

可能会更清楚一点。它的输出是

[edwbuck@phoenix learn_ruby]$ ./ed.p6 
Nil
bar
于 2018-04-18T03:06:35.670 回答
3

这里发生的是惰性列表导致控制流不明显。

这两个函数的返回值都是一个 Seq,其值是通过依次调用值 a、b 和 c 的小 lambda 生成的。知道了这一点,很容易理解为什么你不能改变bar:的返回值,bar甚至在你的 lambda 被第一次调用之前就已经返回了。一旦列表为sayd,则生成所有值并抛出异常。

获得所需内容的正确方法是在地图的结果上调用 .eager ,从而导致在函数返回之前对整个列表进行评估,这使您可以使用它return来更改bar返回的值。

于 2018-04-18T23:25:39.157 回答