此循环永不停止:
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>»
但是我不太确定。
答案 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)
确实是CONTROL
和CX::Succeed
的组合阻止了last
的默认行为。
所有流控制功能都是根据异常实现的。
不是在CATCH
中将它们与常规异常混为一谈,而是为它们专门命名了CONTROL
。
CATCH
和CONTROL
都可以被视为given
的特殊形式。
两个主要区别是主题设置为例外,如果有CX::Succeed
,则会发生一些特殊情况。
如果存在CX::Succeed
,则表明异常或流控制已成功处理,无需进一步处理。
有两种方法可以使CX::Succeed
在CONTROL
内部发生。
default
阻止when
阻止(从技术上讲,我认为仅普通的succeed
也应该起作用,但似乎没有。)
如果您处于这些块之一中,并且希望实际上继续进行处理,则可以使用proceed
(CX::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;
}
}
}