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

2

Log::AnyLog::Any::AdapterをException::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;
}

出力例:

ジョブ exception_job started
5 アイテムを処理しました
...................................................
ワーカーがアイテムの処理に時間をかけすぎた
12秒かかりました。制限は 10 です。

また

ジョブ exception_job started
5 アイテムを処理しました
ワーカーに与えられたアイテムが多すぎて処理できませんでした
残り195点。制限は 100 です。
于 2013-08-19T13:35:20.587 に答える
2

非ローカルな return で思いつくアプローチは、最も内側の関数から例外 (ダイ) をスローすることです。

次に、最上位でそれを処理するためのラッピング コードが必要になります。それを自動的に設定する一連のユーティリティ ルーチンを考案できます。

于 2013-08-19T12:11:30.070 に答える