0

我的问题类似于: Perl 子例程是否可以强制其调用者返回? 但我需要程序方法。

我想编写一些带有返回的消息过程,示例基本代码:

sub PrintMessage {
    #this function can print to the screen and both to logfile
    print "Script message: $_[0]\n";
}

sub ReturnMessage {
    PrintMessage($_[0]);
    return $_[2];  #  <-- we thinking about *this* return
}

sub WorkingProc {
    PrintMessage("Job is started now");
    #some code
    PrintMessage("processed 5 items");

    # this should return from WorkingProc with given exitcode
    ReturnMessage("too many items!",5) if $items>100;

    #another code
    ReturnMessage("time exceded!",6) if $timespent>3600;
    PrintMessage("All processed succesfully");
    return 0;
}

my $ExitCode=WorkingProc();
#finish something
exit $ExitCode

想法是,如何在 ReturnMessage 函数中使用 return 从 WorkingProc 函数中退出指定代码?注意,ReturnMessage 函数在很多地方被调用。

4

3 回答 3

3

这是不可能的。但是,您可以显式返回:

sub WorkingProc {
    PrintMessage("Job is started now");
    ...
    PrintMessage("processed 5 items");

    # this returns from WorkingProc with given exitcode
    return ReturnMessage("to much items!", 5) if $items > 100;

    ...
    return ReturnMessage("time exceded!", 6) if $timespent > 3600;
    PrintMessage("All processed succesfully");
    return 0;
}

一个 sub 可以有任意数量的 return 语句,所以这不是问题。

这样的解决方案比破解调用堆栈更可取,因为控制流对读者来说更明显。你梦想的是一种GOTO45 年前大多数不写 C 或 BASIC 等的人已经放弃了。

您的代码依赖于退出代码来确定子例程中的错误。*叹*。Perl 有一个相当落后的异常系统,但仍然比更先进。

die "Reason"使用、 或use Carp和引发致命错误croak "Reason"Try::Tiny使用orTryCatch模块捕获错误。

sub WorkingProc {
    PrintMessage("Job is started now");
    ...
    PrintMessage("processed 5 items");

    # this should return from WorkingProc with given exitcode
    die "Too much items!" if $items > 100;

    ...
    die "Time exceeded" if $timespent > 3600;
    PrintMessage("All processed succesfully");
    return 0;
}

WorkingProc();

如果抛出错误,它将以非零状态退出。

于 2013-08-19T12:25:29.470 回答
2

对于非本地返回,想到的方法是从最里面的函数抛出异常(死)。

然后,您需要一些包装代码来在顶层处理它。您可以设计一组实用程序来自动设置它。

于 2013-08-19T12:11:30.070 回答
2

Log::AnyLog::Any::AdapterException::Class结合使用可以让您以最小的麻烦和最大的灵活性将所有部分放在一起:

#!/usr/bin/env perl

package My::Worker;
use strict; use warnings;

use Const::Fast;
use Log::Any qw($log);

use Exception::Class (
    JobException => { fields => [qw( exit_code )] },
        TooManyItemsException => {
            isa => 'JobException',
            description => 'The worker was given too many items to process',
        },
        TimeExceededException => {
            isa => 'JobException',
            description => 'The worker spent too much time processing items',
        },
);

sub work {
    my $jobid = shift;
    my $items = shift;

    const my $ITEM_LIMIT => 100;
    const my $TIME_LIMIT => 10;

    $log->infof('Job %s started', $jobid);

    shift @$items for 1 .. 5;
    $log->info('Processed 5 items');

    if (0.25 > rand) {
        # throw this one with 25% probability
        if (@$items > $ITEM_LIMIT) {
            TooManyItemsException->throw(
                error => sprintf(
                    '%d items remain. Limit is %d.',
                    scalar @$items, $ITEM_LIMIT,
                ),
                exit_code => 5,
            );
        }
    }

    { # simulate some work that might take more than 10 seconds
        local $| = 1;
        for (1 .. 40) {
            sleep 1 if 0.3 > rand;
            print '.';
        }
        print "\n";
    }
    my $time_spent = time - $^T;
    ($time_spent > $TIME_LIMIT) and
        TimeExceededException->throw(
            error => sprintf (
                'Spent %d seconds. Limit is %d.',
                $time_spent, $TIME_LIMIT,
            ),
            exit_code => 6);
    $log->info('All processed succesfully');
    return;
}

package main;

use strict; use warnings;
use Log::Any qw( $log );
use Log::Any::Adapter ('Stderr');

eval { My::Worker::work(exceptional_job => [1 .. 200]) };
if (my $x = JobException->caught) {
    $log->error($x->description);
    $log->error($x->error);
    exit $x->exit_code;
}

样本输出:

工作异常_工作开始
已处理 5 件
…………………………………………………………………………………………………………………………………………
工人花太多时间处理物品
花了12秒。限制为 10。

或者

工作异常_工作开始
已处理 5 件
工人被分配了太多需要处理的物品
还剩 195 件。限制为 100。
于 2013-08-19T13:35:20.587 回答