可能重复:
是否有可能为一个Perl子程序,迫使它的调用者返回?
我想写这使得呼叫者在一定条件下返回一个子程序。 这是为了被用作用于验证输入到功能的快捷方式。 我至今是:
sub needs($$) {
my ($condition, $message) = @_;
if (not $condition) {
print "$message\n";
# would like to return from the *parent* here
}
return $condition;
}
sub run_find {
my $arg = shift @_;
needs $arg, "arg required" or return;
needs exists $lang{$arg}, "No such language: $arg" or return;
# etc.
}
从来电者返回的优点needs
则是避免不必编写重复or return
内部run_find
和类似的功能。
我想你集中于错误的东西在这里。 我做这样的使用数据::约束,事情砖等,在掌握Perl的谈论这个。 随着一点点的小聪明和思考你的程序的结构和Perl有动态的功能,你不需要这样的严格管制,程序方法。
不过,你需要弄清楚的第一件事情是你真正想要的,调用子程序知道。 如果你只是想知道是或否,这是很容易。
您的问题needs
是,你想叫它一次每一个条件,这迫使你使用needs
来控制程序流程。 这是错误的路要走。 needs
的只是有没有给你一个答案。 它的工作是不会改变程序的状态。 它成为你滥用它,因为一些其他的调用子程序可能要继续即使更有效needs
返回false。 呼叫一次,让它回归一次。 主叫使用子程序的返回值来决定什么应该做的。
其基本结构涉及您传递到表needs
。 这是你的验证配置文件。
sub run_find {
my $arg = shift @_;
return unless needs [
[ sub { $arg }, "arg required" ],
[ sub { exists $lang{$arg} }, "No such language: $arg" ],
];
}
...
}
您建造表无论您的要求。 在needs
你只是处理表:
sub needs($$) {
my ($table) = @_;
foreach $test ( @$table ) {
my( $sub, $message ) = @$test;
unless( $sub->(...) ) {
print $message;
return
}
}
return 1;
}
现在,这种方法的很酷的事情是,你不必提前知道时间的表。 你可以拉,从配置或其他方法。 这也意味着,你可以动态改变该表。 现在,你的代码缩小了不少:
sub run_find {
my $arg = shift @_;
return unless needs( $validators{run_find} );
...
}
您中央社跟上这是怎么回事。 在掌握Perl中我展示了几个解决方案完全从代码中删除,并将其移动到一个配置文件。 也就是说,你可以改变业务规则,而无需修改代码。
请记住,几乎任何时候您键入的字符相同的序列,你可能就错了。 :)
听起来你是重新发明的异常处理。
在needs
函数不应该神奇地演绎其母公司和打断父母的控制流-这是不礼貌的。 如果您添加额外的功能调用链,而你需要回去两个甚至三个功能恢复? 你怎么能编程方式确定这一点? 将来电者是希望他或她的功能,以提前返回? 您应该遵循最小惊讶的原则,如果你希望避免的错误 - 这意味着使用异常,表明有一个问题,并且具有来电者决定如何处理它:
use Carp;
use Try::Tiny;
sub run_find {
my $arg = shift;
defined $arg or croak "arg required";
exists $lang{$arg} or croak "no such language: $arg";
...
}
sub parent {
try { run_find('foo') }
catch { print $@; }
}
在内部的任何代码try
块是特殊的:如果事情死亡,异常被捕获并存储在$@
。 在这种情况下, catch
块被执行,打印出错误到STDOUT和控制流程继续正常进行。
免责声明:在Perl异常处理是一种痛苦。 我建议尝试::微小的 ,这可以防止许多常见的问题(并提供了熟悉的try / catch语句语义)和异常::类快速做出例外对象,这样你就可以Perl的错误和自己区别开来。
对于参数验证,您可能会发现它更容易使用一个CPAN模块,如PARAMS ::验证 。
你可能想看看通过kinopiko类似最近的问题: 是否有可能在一个Perl子程序,迫使它的调用者返回?
该执行摘要:最好的办法是使用异常(模/ EVAL,尝试::微小,等...)。 您也面包车使用GOTO和可能延续::逃生
它没有意义的,这样做事; 讽刺的是,雅并不需要needs
。
这里的原因。
-
run_find
是写得不好。 如果你的第一个条件是真实的,你永远不会测试第二个,因为你必须return
版了。 - 该
warn
和die
的功能将为您提供打印和/或退出反正行为。
这是我会怎么写你run_find
子,如果你想终止执行,如果你的论点失败(重新命名为well_defined
):
sub well_defined {
my $arg = shift;
$arg or die "arg required";
exists $lang{$arg} or die "no such language: $arg";
return 1;
}
应该有一种方式return 0
,并warn
在同一时间,但我需要用它玩多一点。
run_find
也可以写入到return 0
和适当的warn
消息,如果条件没有得到满足,并return 1
,如果它们(重命名为well_defined
)。
sub well_defined {
my $arg = shift;
$arg or warn "arg required" and return 0;
exists $lang{$arg} or warn "no such language: $arg" and return 0;
return 1;
}
这使得布尔式的行为,如下面所示:
perform_calculation $arg if well_defined $arg; # executes only if well-defined