2

我正在编写一个游戏系统(战争游戏等),并正在创建用于创建和显示十六进制地图的系统。我很快意识到我在重复执行 x=(0..maxx) 和 y=(0..maxy) 的嵌套循环。所以我尝试修改我在某处找到的一些代码(高级 perl 书籍之一,我忘记了在哪里),以创建一种更简单的方法来执行这种循环操作。这就是我想出的:

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);
        }
    }
}

它应该像 一样工作sort,但使用$xand$y而不是$aand $b

注意:警告语句用于调试。我还简化了 x 和 y 范围(传入的数组确定了 maxx 和 maxy 值,但我不想用计算它们的例程混淆这个讨论......我只是将它们硬编码为 maxx=5 和最大值=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"; } '...';

our ($x, $y);您可以通过使用$aand$b而不是$xand来避免需要$y。您无法通过将其(或use vars qw( $x $y );)移入来解决问题,fillmap因为您显然打算fillmap在与调用者不同的包和词法范围中使用。

于 2012-07-25T16:30:36.590 回答