控制还是一旦与最后一团糟?

时间:2019-06-27 05:04:01

标签: exception perl6

此循环永不停止:

class CX::Vaya does X::Control {
    has $.message
}

loop {
    once {
        CX::Vaya.new( message => "I messed up!" ).throw;
    }
    last;
    CONTROL {
        default {
            say "Controlled { .^name }: { .message }"
        }
    }
}

它一直在写

Controlled CX::Last: <last control exception>
Controlled CX::Last: <last control exception>
Controlled CX::Last: <last control exception>
Controlled CX::Last: <last control exception>
Controlled CX::Last: <last control exception>
Controlled CX::Last: <last control exception>
Controlled CX::Last: <last control exception>
Controlled CX::Last: <last control exception>
...

可能是once位,因为最后一个CONTROL移相器确实完成了:

loop { say "Hey"; last; CONTROL { default: .message.say } }
# OUTPUT: «Hey␤<last control exception>␤»

但是我不太确定。

3 个答案:

答案 0 :(得分:13)

Perl 6中的循环流控制是使用控制异常实现的。因此,last实际上引发了CX::Last控制异常。由于CONTROL块使用default,因此它捕获了CX::Last抛出的last,这意味着控制永远不会移出循环。

解决方法是改为使用when指定要捕获的控件异常:

loop {
    once {
        CX::Vaya.new( message => "I messed up!" ).throw;
    }
    last;
    CONTROL {
        when CX::Vaya {
            say "Controlled { .^name }: { .message }"
        }
    }
}

答案 1 :(得分:7)

乔纳森怎么说。

详细信息:

  • P6的默认控制流程是下一条语句紧随当前语句。因此,say 42; say 99;默认先执行say 42,然后再执行say 99

  • P6具有一个高级且广泛使用的异常系统,该系统用于此语句的默认控制流的任何异常,然后立即执行以下语句。不仅仅是错误。

  • 默认控制流的任何异常都称为异常。许多是错误异常。但是还有另一种类别,即控制流异常或简称为 control exception 。例如,例程/块中的显式或隐式return / leave是控制异常。 (原则上。实际上,编译器/优化器会在适当的时候忽略其中的某些机制。)

  • last是控制异常。它将引发控制异常CX::Last。其消息有效负载为"last control exception"。您正在看到该消息。

  • 如果控制异常应用于其包含的块,则将输入CONTROL块。它可以处理传递的异常,也可以不处理。如果处理,则控制将继续执行其后的语句。如本例中所示,如果CONTROL块位于循环的末尾,则下一条语句将是隐式的next(另一个控制异常),并且循环将重新开始。

  • 代码CONTROL { default { say "Controlled { .^name }: { .message }" }处理所有 控制异常,包括last引发的异常。因此它将打印其消息,然后循环继续。 (无限。)

  • 在代码loop { say "Hey"; last; CONTROL { default: .message.say } } # OUTPUT: «Hey␤<last control exception>␤»中,CONTROL块会显示异常的消息,但不会处理。 (default:只是一个标签,与I'm-a-label:一样,并且与default { ... }无关。)因此,last控件异常不会由您的代码处理,而是由默认的语言处理来处理。

答案 2 :(得分:4)

确实是CONTROLCX::Succeed的组合阻止了last的默认行为。


所有流控制功能都是根据异常实现的。

不是在CATCH中将它们与常规异常混为一谈,而是为它们专门命名了CONTROL

CATCHCONTROL都可以被视为given的特殊形式。
两个主要区别是主题设置为例外,如果有CX::Succeed,则会发生一些特殊情况。

如果存在CX::Succeed,则表明异常或流控制已成功处理,无需进一步处理。


有两种方法可以使CX::SucceedCONTROL内部发生。

  1. default阻止
  2. when阻止

(从技术上讲,我认为仅普通的succeed也应该起作用,但似乎没有。)

如果您处于这些块之一中,并且希望实际上继续进行处理,则可以使用proceedCX::Proceed)。

loop {
    once {
        CX::Vaya.new( message => "I messed up!" ).throw;
    }
    last;

    CONTROL {
        default {
            .^name.say;
            proceed if CX::Last;
        }
    }
}

最好使用when块来捕获您要专门处理的内容。
(请注意,后缀when不会抛出CX::Succeed,因此在这种情况下将继续正常处理。)


default是一个块前缀。意味着必须始终在其后加上一个块。

在标识符的末尾仅添加:仅用于创建标签,并在方法调用中用于删除括号。

所以default:在这里绝对不做任何事情。

once不是一个块前缀。它是一个语句前缀。 (碰巧将一个块视为一条语句。)
除非您要在其中添加多个语句,否则没有理由在其中添加一个块。


loop {
    once CX::Vaya.new( message => "I messed up!" ).throw;
    last;

    CONTROL {
        when CX::Vaya {
            .^name.say;
        }
    }
}