我正致力于编写游戏系统(战争游戏等),并正在创建用于创建和显示十六进制地图的系统。我很快意识到我一再做一个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未定义)。
我做错了什么?
答案 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
用于与调用者不同的包和词法范围。