未记载的Perl变量%_?

Cha*_*had 21 perl

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

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

$ perl
use strict;
use warnings;
print keys %_;
$
Run Code Online (Sandbox Code Playgroud)

所以,我能想到的%_只是在某处定义的.我找不到它perlvar,所以这是什么交易?它在上面的脚本中没有任何内容.

ike*_*ami 22

标点变量免于严格.这就是为什么你不必使用our $_;之前使用的东西$_.来自perlvar,

以数字,控制字符或标点符号开头的Perl标识符也可免于strict 'vars'错误.


%_没有证件.来自perlvar,

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

您可以使用名为hash的哈希,_因为它_是变量的有效名称.(我相信你很熟悉$_@_.)

没有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::_
Run Code Online (Sandbox Code Playgroud)

这意味着忘记使用local %_(如你所做)可能会产生非常深远的影响.

  • 当你使用'%_`时Perl没有给出任何警告是很蹩脚的:它保留给Perl,但是Perl并没有赋予它任何意义,因此任何使用它几乎肯定是某种错误. (2认同)

Bor*_*din 15

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

perldoc perlvar说这个

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

所以%_保留但未被使用.

哈希变量是最常见的,所以你会发现,你可以用%1,%(等,以及(类似的代码$({xx} = 99是好的),但你会得到不因向后兼容性问题的警告

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


Thi*_*Not 6

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

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

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

所有上述条目都是typeglobs,由*sigil 表示.一个类型团,如同与对所有的不同的Perl类型的时隙的容器(例如SCALAR,ARRAY,HASH,CODE).

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
Run Code Online (Sandbox Code Playgroud)

的值$_,@_%_都存储在main与主要符号表项_.当您访问时%_,您实际上正在访问typeglob中的HASH插槽*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
Run Code Online (Sandbox Code Playgroud)