3

我有一个更新 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

4 回答 4

9

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

于 2013-01-24T01:26:11.200 回答
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,chomp,chr,chroot,cos,定义,eval,exp,glob,hex,int,lc,lcfirst,长度,log,lstat,mkdir,oct,ord,pos,print,quotemeta,readlink, readpipe、ref、require、reverse(仅在标量上下文中)、rmdir、sin、split(在其第二个参数上)、sqrt、stat、study、uc、ucfirst、unlink、unpack。

  • 除了默认为 STDIN的所有文件测试 ( -f, -d) 。-t-Xperlfunc

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

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

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

  • 的隐含变量given()

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

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

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

于 2013-01-24T02:34:31.653 回答
5

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

于 2013-01-24T01:32:50.017 回答
0

$_默认情况下不是由 void 上下文中的子例程设置的。可以编写您的潜艇来设置$_何时是无效上下文。您首先检查 的值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;
  }
}

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

我唯一一次这样做是在模拟内置子程序时。

于 2013-01-31T03:57:48.493 回答