例程作为参数 - 通用变量不起作用

时间:2012-07-25 15:52:01

标签: perl

我正致力于编写游戏系统(战争游戏等),并正在创建用于创建和显示十六进制地图的系统。我很快意识到我一再做一个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一样工作,但使用$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未定义)。

我做错了什么?

1 个答案:

答案 0 :(得分: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);$a代替$b$x来避免使用$y。你无法通过将它(或use vars qw( $x $y );)移动到fillmap来解决问题,因为你显然希望fillmap用于与调用者不同的包和词法范围。