2011-11-15 15 views
3

私は、このようにヘルパー関数での発送のハッシュとして実装される機能のセットを持つモジュールを持っている:たPerl:派遣ハッシュと共有変数

my $functions = { 
    'f1' => sub { 
     my %args = @_; 
     ## process data ... 
     return $answer; 
    }, 
[etc.] 
}; 

sub do_function { 
    my $fn = shift; 
    return $functions->{$fn}(@_); 
} 

。これは、そのプロセスタブ区切りのデータをいくつかのスクリプトによって使用されます。調べる列は適切なサブルーチンによって変換されます。列の値を処理するとき、データのハッシュをサブに渡し、列の新しい値であるスカラーを生成します。 、私の$はERRS、など。他の値を更新することが可能である私の$データ -

my $new_value = do_function('f1', data => $data, errs => $errs); 

と引数の変数は、すべての「私」として宣言されます。

は現在、潜水艦は、このように呼ばれていますそれらを返さなくてもサブシステムに渡される引数には?すなわち、代わりにこれを実行することの:私はこれを行うことができます

... in $functions->{f1}: 
     my %args = @_; 
     ## process data ... 
     ## alter $args{errs} 
     $args{errs}->{type_one_error}++; 
     ## ... 
     return { answer => $answer, errs => $args{errs} }; 
... 

## call the function, get the response, update the errs 
my $return_data = do_function('f1', data => $data, errs => $errs); 
my $new_value = $return_data->{answer}; 
$errs = $return_data->{errs}; ## this has been altered by sub 'f1' 

my $new_value = do_function('f1', data => $data, errs => $errs); 
    ## no need to update $errs, it has been magically updated already! 

答えて

3

あなたは価値とサブルーチンの内部でそれを更新するための参照を渡すことができます。例えば

sub update { 
    my ($ref_to_value) = @_; 
    $$ref_to_value = "New message"; 
    return "Ok"; 
} 

my $message = "Old message"; 

my $retval = update(\$message); 

print "Return value: '$retval'\nMessage: '$message'\n"; 

そして限り、私はあなたのコードスニペットから見ることができるように、$errsはすでにハッシュへのリファレンスです。 だから、実際には、すべてあなたがしなければならない - 私はあなたのコードの権利を取得する場合は、単に

をライン$errs = $return_data->{errs};をコメントアウトしてみてください、$errsが更新されます。そして、あなただけ$answerにあなたの戻り値を変更して実行する必要があります。新しいサブルーチンに派遣するための適切な方法をある

sub do_function { 
    my $fn = shift; 
    goto &{$functions->{$fn}} 
} 

my $new_value = do_function('f1', data => $data, errs => $errs); 
+0

キーの一部/すべてをローカライズ美しい、感謝:あなたはすべての新しい値をコピーしたい場合は、のいずれかを使用することができます! –

+0

@girlwithglassesさん、ありがとうございます。これで問題は解決しますか? – yko

+0

はい、それは私のperlの生活を最も楽しくしました。ありがとうございました! –

1
  • は、最初にdo_functionのあなたの定義を変更します。この形式のgotoは、現在実行中のサブルーチンを新しいコードリーダに置き換え、@_をそのまま渡し、コールスタックからdo_functionを削除します(callerが正しく機能します)。 $fnが有効な名前であることを確認するために、おそらく何らかのエラーチェックが必要になります。

  • あなたの関数内では、単に@_のセルを直接変更することができます。また、参照によって何も渡す必要はありません(perlはすでにそれを行っているので)。

    sub add1 {$_[0]++} 
    my $x = 1; 
    add1 $x; 
    say $x; # 2 
    

    あなたはそれをこのように書くことができ、参照によって渡さずkey => value引数をサポートする:

    in $functions->{f1}: 
        my %args; 
        while (@_) { 
         $args{$_} = /errs/ ? \shift : shift for shift 
        } 
        ## process data ... 
        ## alter ${$args{errs}} 
        ## ... 
    
  • もつともあなたのケースで$errsは、ハッシュリファレンスであることから、あなたは何をする必要はありません。余分な仕事。すべての参照は自動的に参照渡しされます。あなたの既存のコードでは、$args{errs}のキーを変更するだけです(あなたが今行っているように)、そのハッシュへのすべての参照を変更します。あなたが機能ローカルハッシュを望んでいた場合

    は、あなたはハッシュ*のコピーを作成する必要があります。%errsがプライベートで、作業が完了したら、あなたはあなたがしたい任意の値をプッシュすることができ

    my %errs = %{$args{errs}}; 
    

    公衆には$args{errs}$args{errs}{...} = ...;が含まれています。 $args{errs}をコピーして($args{errs} = \%errsのように)、呼び出し元のエラーハッシュへの接続が切断されることがないようにしてください。 *

    %{$args{errs}} = %errs;        # replace all keys 
    @{$args{errs}}{keys %errs} = values %errs;   # replace keys in %errs 
    ... and $args{errs}{$_} = $errs{$_} for keys %errs; # conditional replace 
    

    または

+0

包括的な回答をいただきありがとうございます。 –

+0

今日このコードをもう一度使用しました。この非常に便利な説明にもう一度感謝します! –