我正在编写一个游戏系统(战争游戏等),并正在创建用于创建和显示十六进制地图的系统。我很快意识到,我正在重复执行x=(0.maxx)和y=(0..maxy)的嵌套循环。因此,我试图调整我在某个地方找到的一些代码(我忘记了在哪里),以创建一种更容易的方式来进行这种循环。这就是我想到的:
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,$yn";
&{$code}($x,$y);
}
}
}
假设它的工作方式与sort
类似,但使用$x
和$y
而不是$a
和$b
。
注意:warn语句用于调试。我还简化了x和y范围(传入的数组确定了maxx和maxy值,但我不想用计算它们的例程来搅乱讨论……我只是将它们硬编码为maxx=5和maxy=3)
所以,这个例程的执行是这样的:
fillmap {warn "$x,$yn";} @map;
应该生成一个x,y对的列表。但相反,它给了我这个:
fillmap 0,0
,
fillmap 0,1
,
fillmap 0,2
,
fillmap 0,3
,
fillmap 1,0
,
...
注意,"fillmap"行来自用于调试的子例程。但是,我只得到逗号($x和$y未定义),而不是每个x,y对。
我做错了什么?
问题是for $x
有自己的本地化。循环中的$x
不是别名为$caller::x
的$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,$yn"; } '...';
使用$a
和$b
代替$x
和$y
可以避免对our ($x, $y);
的需要。您无法通过将它(或use vars qw( $x $y );
)移动到fillmap
来解决问题,因为您显然希望fillmap
在与调用者不同的包和词法范围中使用。