16

使用して比較 perl -w -Mstrict

# case Alpha
print $c;

..。

# case Bravo
if (0) {
  my $c = 1;
}

print $c;

..。

# case Charlie
my $c = 1 if 0;
print $c;

AlphaそしてBravo両方とも、グローバルシンボルに明示的なパッケージ名がないことについて不平を言っています。これは予想されることです。ただしCharlie、同じ警告は表示されません。値が初期化されていないというだけで、次のようなにおいがします。

# case Delta
my $c;
print $c;

ボンネットの下で正確に何が起こっているのですか?(このようなものを本番コード用に作成することはできませんが)

4

3 に答える 3

15

my宣言は、コンパイル時と実行時にアクションを持つと考えることができます。コンパイル時に、my宣言は、シンボルが存在し、現在の字句スコープが終了するまで使用可能になることをメモするようにコンパイラーに指示します。その宣言でのシンボルの割り当てまたはその他の使用は、実行時に行われます。

だからあなたの例

my $c = 1 if 0;

のようなものです

my $c;         # compile-time declaration, initialized to undef
$c = 1 if 0;   # runtime -- as written has no effect

このコンパイル時/実行時の区別により、このようなコードを記述できることに注意してください。

my $DEBUG;    # lexical scope variable declared at compile-time
BEGIN {
    $DEBUG = $ENV{MY_DEBUG};   # statement executed at compile-time
};

今、あなたはこのプログラムの出力が何であるかを推測できますか?

my $c = 3;
BEGIN {
    print "\$c is $c\n";
    $c = 4;
}
print "\$c is $c\n";
于 2012-06-29T20:22:04.563 に答える
8

暴徒の答えperldoc perlsynは、現在何が起こっているのか(そしてその理由)の素晴らしい説明ですが、それが私たちに教えてくれることを忘れないでください:

注:my、、、stateまたはourステートメント修飾子の条件付きまたはループ構造(たとえばmy $x if ...)で変更された動作は未定義です。my変数 の値は、undef以前に割り当てられた値、または場合によっては他の値にすることができます。それに頼らないでください。将来のバージョンのperlは、試してみたバージョンのperlとは異なる動作をする可能性があります。ここにドラゴンがいます。

その結果や、Perlの将来のバージョンでもそれが真実であるという説明を当てにしないでください。(おそらくそうなるでしょうが。)

于 2012-06-30T15:29:50.303 に答える
3

「my$foo = val if cond」コンストラクトとその未定義動作は、何年にもわたって何度も私を噛みました。コンパイラが単にそれを拒否できればいいのですが(なぜ未定義の動作をする言語で何かを保持するのですか?!)、おそらくこれは下位互換性またはその他の理由で実行できません。私が見つけた最善の解決策は、perlcriticでそれを防ぐことです:

http://search.cpan.org/perldoc?Perl::Critic::Policy::Variables::ProhibitConditionalDeclarations

于 2012-07-02T16:12:31.017 に答える