一个Perl如何强制它的调用者返回? [重复](How can a Perl force its

2019-10-22 04:34发布

可能重复:
是否有可能为一个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和类似的功能。

Answer 1:

我想你集中于错误的东西在这里。 我做这样的使用数据::约束,事情砖等,在掌握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中我展示了几个解决方案完全从代码中删除,并将其移动到一个配置文件。 也就是说,你可以改变业务规则,而无需修改代码。

请记住,几乎任何时候您键入的字符相同的序列,你可能就错了。 :)



Answer 2:

听起来你是重新发明的异常处理。

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 ::验证 。



Answer 3:

你可能想看看通过kinopiko类似最近的问题: 是否有可能在一个Perl子程序,迫使它的调用者返回?

该执行摘要:最好的办法是使用异常(模/ EVAL,尝试::微小,等...)。 您也面包车使用GOTO和可能延续::逃生



Answer 4:

它没有意义的,这样做事; 讽刺的是,雅并不需要needs

这里的原因。

  • run_find是写得不好。 如果你的第一个条件是真实的,你永远不会测试第二个,因为你必须return版了。
  • warndie的功能将为您提供打印和/或退出反正行为。

这是我会怎么写你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


文章来源: How can a Perl force its caller to return? [duplicate]