我有一个Perl例程来管理错误检查。基于先前的成功,大约有10种不同的检查,有些是嵌套的。这些通常不是特殊情况,我需要croak
/ die
。此外,一旦发生错误,执行其余检查就没有意义了。
但是,我似乎无法想出一个简洁的方法来解决这个问题,除非使用类似于以下可怕黑客的东西:
sub lots_of_checks
{
if(failcond)
{
goto failstate:
}
elsif(failcond2)
{
goto failstate;
}
#This continues on and on until...
return 1; #O happy day!
failstate:
return 0; #Dead...
}
我希望能做的事情是这样的:
do
{
if(failcond)
{
last;
}
#...
};
答案 0 :(得分:12)
空返回语句是从Perl子返回false
而不是返回0
的更好方法。后一个值在列表上下文中实际上是真的:
sub lots_of_checks {
return if fail_condition_1;
return if fail_condition_2;
# ...
return 1;
}
答案 1 :(得分:8)
也许您想查看以下有关perl5中异常处理的文章:
答案 2 :(得分:5)
你绝对可以做你喜欢的事。
Check: {
last Check
if failcond1;
last Check
if failcond2;
success();
}
答案 3 :(得分:5)
为什么不使用例外?任何不应遵循代码正常流程的情况都是例外。使用“return”或“goto”实际上是相同的,只是“不是你想要的”。
(你真正想要的是延续,“return”,“goto”,“last”和“throw”都是特殊情况。虽然Perl没有完整的延续,但我们确实有逃避延续;请参阅{ {3}})
在您的代码示例中,您编写:
do
{
if(failcond)
{
last;
}
#...
};
这可能与:
相同eval {
if(failcond){
die 'failcond';
}
}
如果你想变得棘手而忽略其他例外:
my $magic = [];
eval {
if(failcond){
die $magic;
}
}
if ($@ != $magic) {
die; # rethrow
}
或者,您可以使用上面提到的Continuation :: Escape模块。但 没有理由忽视异常;这是完全可以接受的 以这种方式使用它们。
答案 4 :(得分:4)
根据你的例子,我会这样写:
sub lots_of_checks {
local $_ = shift; # You can use 'my' here in 5.10+
return if /condition1/;
return if /condition2/;
# etc.
return 1;
}
请注意return
而不是return 0
。这通常更好,因为它尊重背景;标量上下文中的值为undef
,列表上下文中的值为()
(空列表)。
如果你想保持一个单一的退出点(稍微不是Perlish),你可以不用goto
来做到这一点。作为last
州的文档:
...一个块本身在语义上与执行一次的循环相同。 因此,“最后”可用于实现早期退出此类块。
sub lots_of_checks {
local $_ = shift;
my $all_clear;
{
last if /condition1/;
last if /condition2/;
# ...
$all_clear = 1; # only set if all checks pass
}
return unless $all_clear;
return 1;
}
答案 5 :(得分:2)
如果您想保留单个输入/单输出结构,可以稍微修改其他建议以获取:
sub lots_of_checks
{
goto failstate if failcond1;
goto failstate if failcond2;
# This continues on and on until...
return 1; # O happy day!
failstate:
# Any clean up code here.
return; # Dead...
}
IMO,Perl使用语句修饰符形式“如果EXPR返回”使得保护条款比C语言更具可读性。当您第一次看到该行时,您知道您有一个保护条款。这个功能经常被诋毁,但在这种情况下我非常喜欢它。
将goto
与语句修饰符一起使用可保留清晰度,并减少混乱,同时保留单一退出代码样式。当我在例行程序验证失败后进行复杂的清理时,我已经使用过这种形式。