为什么我的子例程返回值没有分配给$ _ default变量

时间:2013-01-24 01:23:18

标签: perl

我有一个更新RSS源的Perl子例程。我想测试返回的值,但是函数在很多地方使用,所以我只想测试默认变量$_,据我所知,如果没有指定变量,应该为其分配返回值。

代码有点太长而无法包含所有内容,但实质上它会执行以下操作

sub updateFeed {
  #....
  if($error) {
    return 0;
  }
  return 1;
}

为什么会这样做

$rtn = updateFeed("My message");
if ($rtn < 1) { &Log("updateFeed Failed with error $rtn"); }

不记录任何错误

,而

updateFeed("myMessage");
if ($_ < 1) { &Log("updateFeed Failed with error $_"); }

记录错误“updateFeed Failed with error”? (注意消息末尾没有值。)

有谁能告诉我为什么默认变量似乎包含空字符串或undef?

4 个答案:

答案 0 :(得分:9)

因为Perl不能那样工作。 $_不会自动获取void上下文中调用的函数的结果。默认情况下,有一些内置运算符可以读写$_@_,但是如果你编写代码来实现它,你自己的子程序就会这样做。

答案 1 :(得分:7)

普通函数调用不是隐式使用$_的上下文之一。

以下是perldoc perlvar(截至v5.14.1)对$_所说的内容:

  

$ _
  默认输入和模式搜索空间。以下对是等价的:

    while (<>) {...}    # equivalent only in while!
    while (defined($_ = <>)) {...}

    /^Subject:/
    $_ =~ /^Subject:/

    tr/a-z/A-Z/
    $_ =~ tr/a-z/A-Z/

    chomp     
    chomp($_) 
  

以下是Perl假设$ _的地方,即使你不使用它:

     
      
  • 以下函数使用$ _作为默认参数:

         

    abs,闹钟,chomp,印章,chr,chroot,cos,定义,eval,exp,glob,hex,int,lc,lcfirst,长度,日志,lstat,mkdir,oct,ord,pos,打印,quotemeta ,readlink,readpipe,ref,require,   反向(仅在标量上下文中),rmdir,sin,split(在其第二个参数上),sqrt,stat,study,uc,ucfirst,unlink,unpack。

  •   
  • 所有文件测试(-f-d)除了-t,默认为STDIN。请参阅perlfunc中的-X

  •   
  • 在没有m//运算符的情况下使用模式匹配操作s///tr///y///(又名=~)。

  •   
  • 如果没有提供其他变量,则foreach循环中的默认迭代器变量。

  •   
  • grep()map()函数中的隐式迭代器变量。

  •   
  • 隐含变量given()

  •   
  • <FH>操作的结果作为while测试的唯一标准进行测试时,输入记录的默认位置。在while测试之外,这不会发生。

  •   
     

由于$ _是一个全局变量,这可能会在某些情况下导致不必要的副作用。从perl 5.9.1开始,您现在可以通过在my的文件或块中声明它来使用$ _的词法版本。   此外,声明our $_恢复当前范围内的全局$ _。

     

助记符:在某些操作中理解下划线。

答案 2 :(得分:5)

你从未将标志分配给$_,为什么它会包含你的旗帜?它似乎包含一个空字符串(或者可能是undef,它带有一个警告字符串化为空字符串。)

答案 3 :(得分:0)

默认情况下,

$_不是由void上下文中的子例程设置的。当void为context时,可以编写你的子集以设置$_。首先检查wantarray的值,并在$_未定义时设置wantarray

sub updateFeed {
  ...
  my $return
  ...

  if($error) {
    $return = 0;
  }else{
    $return = 1;
  }
  # $return = !$error || 0;

  if( defined wantarray ){ # scalar or list context
    return $return;
  }else{ # void context
    $_ = $return;
  }
}

我建议不要这样做,因为对于正在使用你的子程序的人来说这可能是一个惊喜。这可能会使调试程序变得更加困难。

关于我唯一一次这样做,就是模仿built-in subroutine