2009-08-06 12 views
9

私はPerlでのサブルーチンでは、それは例えば、場合には、発信者がそれを使用している、それで何かを行う前localで「デフォルト変数」$_を維持するために非常に良いアイデアだということを知っている:

sub f() { 
    local $_;    # Ensure $_ is restored on dynamic scope exit 
    while (<$somefile>) { # Clobbers $_, but that's OK -- it will be restored 
     ... 
    } 
} 

最初に$_を使用する理由は、正規表現を使用して、$1$2などの便利な「魔法の」変数に結果を入れたいからです。これらの変数も保存したいと思いますが、それを行う方法を見つけることができました。すべてはperlvarは言う

は、内部的に依存して、「現在アクティブな動的スコープで最後に成功したサブマッチ」を参照しているように見える@+@-$1などということです。でも、それは私の実験とは違うようです。私が期待した通り、経験的に、次のコードを印刷「aXaa」:

$_ = 'a'; 
/(.)/;   # Sets $1 to 'a' 
print $1;  # Prints 'a' 
{ 
    local $_; # Preserve $_ 
    $_ = 'X'; 
    /(.)/;  # Sets $1 to 'X' 
    print $1; # Prints 'X' 
} 
print $_;  # Prints 'a' ('local' restored the earlier value of $_) 
print $1;  # Prints 'a', suggesting localising $_ does localise $1 etc. too 

しかし、私は本当に驚くべき発見は私のActivePerl少なくとも5.10.0に、local行をコメントアウトすると、まだ$1を維持する、ということです - つまり、答え「aXXa」が生成されます。中括弧で囲まれたブロックの語彙(動的ではない)範囲は、何とか$1の値を保持しているようです。

私は、この状況が最も混乱していると判断し、決定的な説明を聞きたいと思うでしょう。断っておくが、私は実際にあるとして、それらすべてを列挙することなく、すべて正規表現関連のマジック変数を維持する防弾方法のために解決したい:

local @+, @-, $&, $1, $2, $3, $4, ... 

はっきり嫌なハックです。それまでは、私は正規表現が私に触れると、呼び出し元がclobberedすることを期待していない何かが壊れてしまうのではないかと心配します。

ありがとうございます!

+0

@pilcrow:私はあなたの答えをキャッチしませんでしたが、あなたはそれを削除したと思いますか?とにかく、それは有用な答えだと思っていました。もしあなたがこれを読んでいれば、私は第一の種類の保存を探していました。 2番目は実際には私が望んでいたものではありませんでした。それは、他のスコープにローカルで "出るべき"ものになるでしょう。そう、 "保存" $ 1などを他のローカル変数に追加します。 –

答えて

8

おそらく、ドキュメントのより良い言葉遣いを提案することができます。ダイナミックスコープとは、囲みブロックまたはサブルーチンの開始点までのすべて、およびそのブロックまたはサブルーチン呼び出しの開始までのすべてを意味します。を除くと、閉じられたブロックは除外されます。

「現在アクティブなダイナミックスコープで最後に成功したサブミット」とは、各変数の各ブロックの先頭に暗黙的にlocal $x=$x;があることを意味します。

ダイナミックスコープ(たとえば、http://perldoc.perl.org/perlglossary.html#scopeまたはhttp://perldoc.perl.org/perlglossary.html#dynamic-scoping)のほとんどの言及のうち、 は、逆に近づいています。成功した 正規表現を暗黙的にlocal $1などと考えると、これらは適用されます。

+4

+1。 '$ 1'などは自動的に' local() 'され、スコープは混乱します。 – pilcrow

+0

ありがとう、非常に役立つ!はい、私は(何らかの理由で)ブロックを除外/無視するために取った「ダイナミックスコープ」という用語に混乱しました。 $ 1などが暗黙的にローカライズされていることを知ることは安心です。 (あなたのリンクに基づいて、Perlの文書に明示的に何も言及していないと思いますか?) –

3

これらのすべての変数について、この編集的理由が本当にあるかどうかはわかりません。私はこの文脈で明示的にlocalを使用する必要がなく、Perlをほぼ10年間使用することができました。

あなたの具体的な質問に対する答えは次のとおりです。桁の変数の数は指定されていません(たとえ作業の数にハードメモリの制限がある場合でも)。したがって、それらのすべてを同時にローカライズすることはできません。

+2

@Sinan、それほどではありません。彼らはすでにすべて常にローカルになっています。質問者は、これとおそらくperlの2つのスコープ・パラダイムの複雑さによって、少し混乱します。 – pilcrow

+0

@Sinan:呼び出し元はコール・グラフを一貫してすべての関数が壊れることに常に気を配らなければならないので、呼び出し側の保存は大規模なシステムに拡張できません。したがって、低水準関数の実装を変更して高水準関数を混乱させるのは簡単です。 100行のスクリプトでは問題ありませんが、大きなシステムを作成している場合は、呼び出す関数の実装の詳細について気にしない*ことができなければなりません。 –

+0

しかし、これが問題です。私が呼び出す関数の実装の詳細については気にする必要はありませんでした(さて、 'Win32 :: OLE'を忘れてしまいましょう)。ピクロウの解明を考えれば、それはなぜ明白です。 –

1

あまりにも心配していると思います。

if($string =~ m/...(a.c).../) { 
    my $found = $1; 
    } 

は私がの部分をキャプチャしたいときは:行うための最善のことは、すぐに、それらを気にすることなく、特別な変数は、彼らが何でもしましょう、あなたは意味のある変数に必要な値を保存し、あなたのマッチ演算子を実行しています文字列の場合、よくリストのコンテキストで一致演算子を使用して、メモリのリストを取得します。

my @array = $string =~ m/..../g; 
+0

そこに同意しません:)何年もの間、私は問題を引き起こす可能性は低い等他の関数への呼び出しを変更しないでください)、*保証できない保証がない限り、結局問題を引き起こします*、今日は保証を探します。幸いにも、この場合、ysthはPerlがそのような保証を提供していることを私に示すことができました。 –

+0

Perlが$ 1などを実際に自動ローカライズしなかったとしましょう。そして、最初のコードスニペットがどのように壊れやすいかを簡単に見てください。メンテナンス中にif文が "if($ string =〜m /...(ac).../&some_other_test()){...} "誰かがsome_other_test()の奥深くのどこかで正規表現を追加するまで、すべてうまく動作します。見つかったところでは、奇妙な値が割り当てられています。これは妥当な保守シナリオであることに同意しますか? –

+0

だから、男は医者に行き、 "私はこのように私の腕を動かすと痛い!"と言う。医者は「あなたのように腕を動かさないでください!」と言います。 私の最初のコードスニペットはまったく壊れません。それが問題になっているあなたの変化です。私は意図的に業務を孤立させました。あなたは私が言うことをしない:すぐに結果を保存する。 –

関連する問題