未记载的Perl变量%_?

时间:2016-04-19 16:04:11

标签: perl

我最近在Perl %_中发现了一个似乎是未记录的变量。我不记得我是如何偶然发现的(这是上周),但我的代码中有一个拼写错误,我使用的是map而不是$_->{key}我使用{{1} }}。当我发现错误时,我很惊讶它没有产生错误,我确认$_{key}use strict已经到位。

所以,我做了一个小测试,确定它运行时没有任何警告或错误:

use warnings

所以,我能想到的是$ perl use strict; use warnings; print keys %_; $ 在某处定义。我无法在%_找到它,那么这笔交易是什么?它在上面的脚本中没有任何内容。

3 个答案:

答案 0 :(得分:22)

标点变量免于严格。这就是为什么在使用our $_;之前不必使用$_之类的内容。来自perlvar,

  

以数字,控制字符或标点字符[...]开头的Perl标识符也不会出现strict 'vars'错误。

%_没有记录。来自perlvar,

  

Perl变量名也可以是数字序列或单个标点符号或控制字符(不推荐使用文字控制字符形式)。这些名称都保留给Perl的特殊用途

您可以使用名为_的哈希,因为_是变量的有效名称。 (我确信您熟悉$_@_。)

没有Perl内置程序当前设置它或隐式读取%_,但保留标点变量,如%_

请注意,标点符号变量也很特殊,因为它们是“超级全局变量”。这意味着不合格的%_引用根包中的%_,而不是当前包中的%_

$ perl -E'
   %::x    = ( "%::x"    => 1 );
   %::_    = ( "%::_"    => 1 );
   %Foo::x = ( "%Foo::x" => 1 );
   %Foo::_ = ( "%Foo::_" => 1 );

   package Foo;
   say "%x      = ", keys(%x);
   say "%_      = ", keys(%_);
   say "%::x    = ", keys(%::x);
   say "%::_    = ", keys(%::_);
   say "%Foo::x = ", keys(%Foo::x);
   say "%Foo::_ = ", keys(%Foo::_);
'
%x      = %Foo::x
%_      = %::_      <-- surprise!
%::x    = %::x
%::_    = %::_
%Foo::x = %Foo::x
%Foo::_ = %Foo::_

这意味着忘记使用local %_(正如您所做的那样)会产生非常深远的影响。

答案 1 :(得分:15)

它没有记录,它只是未使用。你会发现它总是空的

perldoc perlvar说这个

  

Perl变量名也可以是数字序列或单个标点符号或控制字符......这些名称都保留给Perl的特殊用途;例如,全数字名称用于保存正则表达式匹配后由反向引用捕获的数据。

所以%_ 保留但未使用。

哈希变量是最不常见的,所以你会发现你也可以使用%1%(等等(像$({xx} = 99这样的代码很好)但你不会得到任何警告因为后向兼容性问题

有效的通用变量名必须以字母开头(utf8编译指示可以是任何具有Unicode 字母属性的字符)或ASCII下划线,当它必须至少跟一个其他角色

答案 2 :(得分:6)

$_是一个全局变量。全局变量位于symbol tables,内置标点符号变量全部存在于包main的符号表中。

您可以看到main符号表的内容,如下所示:

$ perl -MData::Dumper -e'print Dumper \%main::' # or \%:: for short
$VAR1 = { 
          '/' => *{'::/'},
          ',' => *{'::,'},
          '"' => *{'::"'},
          '_' => *::_,
          # and so on
        };

所有上述条目都是typeglobs,由* sigil表示。 typeglob就像一个容器,其中包含所有不同Perl类型的插槽(例如SCALARARRAYHASHCODE)。

typeglob允许您使用具有相同标识符的不同变量(sigil之后的名称):

${ *main::foo{SCALAR} } # long way of writing $main::foo
@{ *main::foo{ARRAY} }  # long way of writing @main::foo
%{ *main::foo{HASH} }   # long way of writing %main::foo

$_@_%_的值都存储在main符号表条目中,密钥为_。当您访问%_时,您实际上正在访问HASH typeglob中的*main::_位置(简称*::_)。

如果您尝试访问没有完全限定名称的全局变量,

strict 'vars'通常会抱怨,但标点符号变量是免除的:

use strict;

*main::foo = \'bar'; # assign 'bar' to SCALAR slot
print $main::foo;    # prints 'bar'
print $foo;          # error: Variable "$foo" is not imported
                     #        Global symbol "$foo" requires explicit package name
print %_;            # no error