请原谅我(可能)愚蠢的问题,但我正在搞乱这个代码(实际上是一个更大程序中的某个模型),有些东西让我失望:
sub recurse {
my $m = shift;
$g .= "::" . $m;
if ($m == 0) { return $g; }
else { $m--; recurse ($m); }
}
for ($i = 0; $i < 3; $i++)
{
my $g = '';
$str = recurse (10);
print $str . "\n";
}
'for'循环的第一次迭代工作正常。然而,在随后的迭代中,我遇到了一个问题。如您所见,在调用递归函数之前,全局变量$ g在'for'循环中首先被重置。使用调试器,我可以看到在调用函数之前$ g被设置回''。但是,只要输入函数'recurse',它就会返回到先前的值。我在这里缺少什么?
作为必然结果,我不喜欢在这里使用全局变量。如果没有为$ recurse()创建$ g参数,那么“正确”的方法是什么?
答案 0 :(得分:7)
my $g
是一个局部变量,因此它与recurse
中使用的变量不同。删除my
将解决这个问题,尽管它仍然是一个丑陋的代码。
您可以将$g
第二个参数传递给resurse
函数。
注意:use strict;
是你的朋友;)
答案 1 :(得分:1)
您可以简单地将g
的定义移出循环之外和函数定义之前。
答案 2 :(得分:1)
正如yi_H所说,你在循环中声明的my $g
是与$g
正在使用的recurse
完全独立的变量。它第一次起作用,因为所有变量都以undef
开头,作为字符串变为空字符串。如果您在调用$g
后尝试在循环内打印recurse
,则会看到它仍为空。使用strict有助于捕获此类错误。它可能会也可能不会发生这种情况,具体取决于程序的其余部分。
处理此问题的最简单方法是将$g
作为参数传递。但是,有时使用递归闭包更容易。请注意,Perl使用引用计数垃圾收集器,这意味着它不能删除自引用数据结构(包括具有对自身的引用的闭包,以便它可以递归地调用自身),直到整个程序退出。我使用weaken中的Scalar::Util函数来避免这种情况。 $strongRef
仅用于防止coderef在我们完成之前被垃圾收集。
use Scalar::Util 'weaken';
for (my $i = 0; $i < 3; $i++)
{
my $g = '';
my $recurse;
my $strongRef = $recurse = sub {
my $m = shift;
$g .= "::" . $m;
if ($m == 0) { return $g; }
else { $m--; $recurse->($m); }
};
weaken($recurse); # Prevent memory leak
my $str = $recurse->(10);
print $str . "\n";
}
但是,在这种特殊情况下,我可能只是直接填充$str
而不是返回值:
for (my $i = 0; $i < 3; $i++)
{
my $str = '';
my $recurse;
my $strongRef = $recurse = sub {
my $m = shift;
$str .= "::" . $m;
if ($m-- > 0) { $recurse->($m); }
};
weaken($recurse); # Prevent memory leak
$recurse->(10);
print $str . "\n";
}
答案 3 :(得分:0)
正如那句老话说的那样,努力工作得到了回报,但懒惰现在已经付出了 。这是代码看起来像我现在决定停止懒惰,并以'正确'方式执行(我还将$ g更改为数组,以避免笨拙的前导分隔符):
use strict;
sub recurse {
my $m = shift;
my @g = qw();
@g = @{$_[0]} if $_[0];
push (@g, $m);
if ($m == 0) { return @g; }
else { $m--; recurse ($m, \@g); }
}
for ( my $i = 0; $i < 3; $i++)
{
my @str = recurse (10);
print join('::', @str) . "\n";
}
答案 4 :(得分:0)
什么是'正确'的方法,没有为$ recurse()创建$ g参数
很简单,因为根本不需要$g
。
sub recurse {
my $m = shift;
if ($m == 0) {
return "::" . $m;
} else {
return "::" . $m . recurse($m-1);
}
}
for ($i = 0; $i < 3; $i++)
{
print recurse(10) . "\n";
}