2

私はゲーム システム (ウォーゲームなど) の作成に取り組んでおり、16 進マップを作成および表示するためのシステムを作成しています。x=(0..maxx) と y=(0..maxy) のネストされたループを繰り返し実行していることにすぐに気付きました。そこで私は、どこかで見つけたコード (高度な perl の本の 1 つ、場所は忘れました) を適応させて、この種のループ処理を行うためのより簡単な方法を作成しようとしました。これは私が思いついたものです:

sub fillmap (&@) {
    my $code = shift;
    no strict 'refs';
    use vars qw($x $y);
    my $caller = caller;
    local(*{$caller."::x"}) = \my $x;
    local(*{$caller."::y"}) = \my $y;
    foreach $x (0..5) {
        foreach $y (0..3) {
            warn "fillmap $x,$y\n";
            &{$code}($x,$y);
        }
    }
}

のように動作すると思われますが、 andの代わりにandsortを使用します。$x$y$a$b

注: warn ステートメントはデバッグ用です。また、x と y の範囲を単純化しました (渡された配列が maxx と maxy の値を決定しますが、これらを計算するためのルーチンでこの議論を混乱させたくありませんでした... maxx=5 にハードコードし、 maxy=3)

したがって、このルーチンのこの実行は次のようになります。

fillmap {warn "$x,$y\n";} @map;

x、yペアのリストを生成する必要があります。しかし、代わりに、それは私にこれを与えます:

fillmap 0,0
,
fillmap 0,1
,
fillmap 0,2
,
fillmap 0,3
,
fillmap 1,0
,
...

「fillmap」行は、デバッグ用のサブルーチンからのものであることに注意してください。ただし、x、y の各ペアの代わりに、コンマを取得するだけです ($x と $y は定義されていません)。

私は何を間違っていますか?

4

1 に答える 1

2

問題はfor $x、独自のローカリゼーションを行うことです。ループの$x内側は、$xにエイリアスされた ではありません$caller::x

次のいずれかを実行する必要があります。

  • ループ内にコピー$xします。$caller::x
  • ループ内$caller::xへのエイリアス。$x

以下は後者を行います:

use strict;
use warnings;

sub fillmap(&@) {
    my $code = shift;

    my $caller = caller();
    my $xp = do { no strict 'refs'; \*{$caller.'::x'} };  local *$xp;
    my $yp = do { no strict 'refs'; \*{$caller.'::y'} };  local *$yp;

    for my $x (0..1) {
        *$xp = \$x;
        for my $y (0..2) {
            *$yp = \$y;
            $code->();
        }
    }
}


our ($x, $y);
fillmap { warn "$x,$y\n"; } '...';

andの代わりにandour ($x, $y);を使用することで、 の必要性を回避できます。呼び出し元とは異なるパッケージおよび字句スコープで使用することを明らかに意図しているため、それ (または) を に移動しても問題を解決することはできません。$a$b$x$yuse vars qw( $x $y );fillmapfillmap

于 2012-07-25T16:30:36.590 に答える