递归函数中的动态范围

时间:2014-07-14 16:09:20

标签: perl recursion

将args传递给递归函数还是让动态范围处理它更好?

sub rec {
  my ($arg1, $arg2 ..) = (@_);
  ..
  rec(..);
}

或者更确切地说:

sub main {
  our ($arg1, $arg2 ..) = (@_);

  sub rec {
    my $arg1 = shift;
    ..  # use $args > 1
    rec($arg1);
}

由于我在main中有几个rec subs,我更喜欢第二个选项,它不需要一直传递vars并减少数量膨胀的代码。说它可能效率不高,因为它会通过每个堆栈帧来解决动态范围?

2 个答案:

答案 0 :(得分:2)

不要将命名子例程放在另一个子例程中。这会导致问题(虽然use warnings;会找到它们)。如果你想避免将常量参数传递给每个递归,我建议改为:

sub recurse {
   my ($constant, ...) = @_;

   local *_recurse = sub {
      my (...) = @_;
      ...
      _recurse(...);
      ...
   };

   _recurse(...);
}

(不知道您使用our的原因。我转回my。)

或者使用足够新版本的Perl(5.16 +):

sub recurse {
   my ($constant, ...) = @_;

   my $_recurse = sub {
      my (...) = @_;
      ...
      __SUB__->(...);
      ...
   };

   $_recurse->(...);
}

无论你做什么,都不要做以下事情,因为它泄漏了。

sub recurse {
   ...
   my $_recurse;
   $_recurse = sub {
      ...
      $_recurse->(...);
      ...
   };
   ...
}

(内部子引用$_recurse,它包含对内部子的引用,形成一个引用循环,从而形成内存泄漏。)

答案 1 :(得分:0)

如果您正在使用依赖于全局变量的递归函数,则几乎可以肯定将其重新编码为使用本地范围变量的迭代子例程。

我强烈建议您始终传递变量并返回值,并重新考虑算法的设计以使用迭代(while循环)与递归。

如果您为方法添加详细信息,我们可能会建议实际实施。但鉴于您分享的信息量,我们所能做的只是建议设计理论。