我最近在Perl %_
中发现了一个似乎是未记录的变量。我不记得我是如何偶然发现的(这是上周),但我的代码中有一个拼写错误,我使用的是map
而不是$_->{key}
我使用{{1} }}。当我发现错误时,我很惊讶它没有产生错误,我确认$_{key}
和use strict
已经到位。
所以,我做了一个小测试,确定它运行时没有任何警告或错误:
use warnings
所以,我能想到的是$ perl
use strict;
use warnings;
print keys %_;
$
在某处定义。我无法在%_
找到它,那么这笔交易是什么?它在上面的脚本中没有任何内容。
答案 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)
它没有记录,它只是未使用。你会发现它总是空的
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类型的插槽(例如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
$_
,@_
和%_
的值都存储在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