逃离递归子程序

时间:2013-02-07 13:52:13

标签: perl

我希望我的代码在特定迭代后退出递归子例程

这是我的测试代码:

#!/usr/bin/perl 
use strict;

&sub();

my $count = 0;
sub sub
{
    if ( $count lt 1 )
    {
        print "This statment is visible \n";
        $count++;
        &sub();
    }
    else
    {
        return;
    }
}

这给出了以下输出,我很满意:

This statment is visible 

但如果我使用#!/usr/bin/perl -w,那么它会给我输出但是也会给我一个警告:

Use of uninitialized value $count in string lt at sub.pl line 9.
This statment is visible

Quistion 1:如何摆脱上述警告。

现在,上面的代码是我的测试代码,我想将相同的逻辑应用于我的实际代码:

简而言之,我想将hostname解析为IP address。如果它不起作用,那么我想将domain name (.my.company.net)附加到hostname,然后尝试名称resoltuion。

然而,我上面的代码(在某些情况下,不知道为什么)会进入无限深度递归并占用整个内存。我的虚拟机变得没有响应,我必须重新启动才能恢复工作。

因此,我希望在一次迭代后摆脱递归子,而不是进行无限递归。

以下是代码:

#!/usr/bin/perl -w
use strict;

my $IP = to_ip("abcdefgh");
print $IP."\n";

my $count = 0;
sub to_ip
{
    if ( $count lt 1 )
    {
        use Socket;
        my $hostname    = shift;
        my $packed_ip   = gethostbyname($hostname);
        if ( defined $packed_ip )
        {
            sprintf inet_ntoa($packed_ip);
        }
        else
        {
            $hostname .= ".my.company.net";
            to_ip($hostname);
        }
        $count++;
    }
    else
    {
        return;
    }
}

Aobve代码给了我低于警告然后再次卡住。我必须重新启动VM才能重新启动它。

Useless use of sprintf in void context at get_deleted_list.pl line 98.

请忽略上述警告中的行号。它指的是我的子

中的sprintf

问题2:如何在一次迭代后摆脱我的sub。我不在乎我是否从sub获得结果但是我想在一次迭代后退出它。

感谢。

2 个答案:

答案 0 :(得分:3)

回答问题1 :将my $count 置于上面的子程序调用:

my $count = 0;
&sub();

sub sub
{
  # ...
}
当你调用sub时,不会声明

$count。它不能用于将其与其他东西进行比较,因此也就是警告。如果没有警告,Perl仍会使用$count执行命令,但不会抱怨。

问题2

首先,将$count放在子程序调用之上。您的sprintf警告告诉您在不使用返回值的情况下呼叫sprintfsprintf格式化字符串并返回它。如果您想输出该字符串,可以说print sprintf $foo,或者只使用printf

一旦你做了两个更改,它将无需在无限循环中运行。至少它对我有用。

另一件事:将子use Socket移到子外面,到最顶端。它在编译时进行评估,因此无论如何都会加载它。如果您希望仅在加载时加载,请改用require SocketSocket::inet_ntoa($packed_ip)

use strict; use warnings;
# use Socket;

my $count = 0;
my $IP = to_ip("abcdefgh");
print $IP. "\n";

sub to_ip {
  if ( $count lt 1 ) {
    my $hostname  = shift;
    my $packed_ip = gethostbyname($hostname);
    if ( defined $packed_ip ) {
      require Socket;                       # instead of use
      print Socket::inet_ntoa($packed_ip);
    } else {
      $hostname .= ".my.company.net";
      to_ip($hostname);
    }
    $count++;
  } else {
    return;
  }
}

答案 1 :(得分:2)

我认为一个简单的基于循环的解决方案会更直接:

sub to_ip
{
  use Socket;
  my $hostname = shift;
  for my $suffix ("", ".my.company.net") {
    my $packed_ip = gethostbyname("$hostname$suffix");
    next unless defined $packed_ip;
    return sprintf inet_ntoa($packed_ip);
  }
 }

这只是按顺序尝试所有替代,直到一个成功,此时它返回所需的字符串。 (顺便说一句,这里真的有sprintf吗?)。如果在没有成功调用gethostbyname的情况下退出循环,则会隐式返回undef。