6

これは SO に関する私の最初の質問です。ばかげている場合は申し訳ありませんが、最近、製品コードで見つけたときに本当に困惑しました。私は自分の問題を 2 つのコード ブロックに要約しました。これは、同じことを行うこと、つまり反復ごとに乱数を生成することを期待していました。

for my $num (0 .. 5) {
    my $id = int rand 10;
    print "$id\n";    
}

for (0 .. 5) {
    my $tmp;
    my $id = $tmp if $tmp;

    $id = int rand 10 unless $id;
    print "$id\n";
}

最初のものは私が期待することをしますが、2番目のものは何回繰り返しても同じ数を与えます。$tmpこの簡略化では常に定義されていないため、= $tmp if $tmp除外すると期待どおりの結果が得られるため、動作を示すだけです。

なぜこれが起こるのかについての洞察をいただければ幸いです。

4

3 に答える 3

11

奇妙な動作の理由は、 の宣言$idそれに代入を、 の真偽を条件として行ったためであり$tmp、これにより Perl は発作を起こします。perldoc perlsynそれについて言いたいことはありますか

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

次のようにコードを変更すると、うまく動作することを自分で実証できます。

for (0 .. 5) {
    my $tmp;
    my $id;
    $id = $tmp if $tmp;

    $id = int rand 10 unless $id;
    print "$id\n";
}
于 2013-01-07T14:42:45.940 に答える
4

a の後のステートメント修飾子の動作は未定義ですmy ...( perlsynを参照)。だからそれを使わないでください...

于 2013-01-07T14:40:17.033 に答える
2

役に立つという理由で長い間意図的に修正されていないバグに出くわしました。この線

my $id = $tmp if $tmp;

ステートメント修飾子 ( if) を変数宣言 ( ) に適用しますmy。変数を条件付きで定義することはあまり意味がありませんmyが、コンパイル時と実行時の両方の動作があるため、これにより効果的に状態変数が作成されます。つまり、囲んでいるブロックに字句的にスコープされているが、その実行間でその値を維持する変数です。ブロック。

見ている動作を (意図的に) 呼び出すための通常の形式は次のとおりです。

my $x if 0;

この動作は Perl 5.10 から廃止され、stateこれをきれいに行うための変数が追加されました。Perl の最新バージョン (5.10 以降) は警告を発します。

Deprecated use of my() in false conditional

バージョン 5.10 より前でさえ、状態変数のエミュレートは、囲みブロックを追加して変数を宣言することによって (簡潔ではありませんが) クリーンに実行できるため、これを使用するのはいくぶん貧弱な形式でした。例えば:

{
  my $n = 0;
  sub increment { return $n++; }
}
于 2013-01-07T16:24:55.490 に答える