perl -Mstrict -wlE 'my %h; say grep 0, $h{poluted}; say keys %h'
输出
poluted
和
perl -Mstrict -wlE 'my %h; say grep 0, my @r= $h{poluted}; say keys %h'
没有输出。
我想知道为什么输出会有所不同?
答案 0 :(得分:13)
在Perl的循环结构map
,grep
和for
中,$_
变量别名到每个当前项。虽然$_
可能是只读的,但它始终代表有效的标量值。
例如,以下代码将死:
$_ = 1 for 1, 2, 3; # constants are read-only
但这有效:
my @nums = (1, 2, 3);
$_ = 1 for @nums; # @nums isn't read-only
请注意,分配执行副本,但别名将名称与现有标量相关联。
undef
值 Perl有两种undef
:
标量可以设置为代表undef
。例如:
my $foo; # is this kind of undef
$foo = 1; # isn't undef any more
一个特殊的全球唯一标量,代表只读undef
值,例如在rvalue上下文中访问未初始化的数组索引时返回。在Perl API中,这是&PL_sv_undef
。您可以获得对此值的引用,例如\undef
,可以别名变量。
在内部,使用hv_fetch
或hv_fetch_ent
提取哈希条目。作为参数,两者都使用哈希,密钥和标志来告诉他们访问是否是只读的。
如果这是只读访问且元素不存在,则返回空指针,该指针在Perl空间中显示为undef
值。此undef
值未与哈希值相关联。因此,not exists $hash{foo}
暗示not defined $hash{foo}
。
但如果它不是只读且元素不存在,则会创建一个新条目,然后返回该条目。但是,此条目最初为undef
,直到通过分配将其设置为其他值。
grep 0, $h{polluted}
循环结构的参数列表别名为$_
。如果列表中的表达式是常量或子程序,那么就不会发生任何惊人的事情。但是当它们是变量访问时,则意味着读写访问。
因此,为了获得$h{polluted}
的值,Perl显然在读写模式下进行访问。如果我们查看这个表达式的操作码,我们实际上看到了:
3 <0> pushmark s
4 <#> gv[*h] s
5 <1> rv2hv sKR/1
6 <$> const[PV "polluted"] s/BARE
7 <2> helem sKM/2 # <-- hash element access, "M" flag is set!
8 <@> grepstart K
9 <|> grepwhile(other->a)[t2] vK
a <$> const[IV 0] s
goto 9
M
代表MOD
,这意味着左值/读写访问。
在for
- 循环中,让$_
成为当前元素的别名可能非常有用。在map
和grep
中,这是一个避免整个标量副本的性能黑客攻击。别名更便宜,因为这只意味着单个指针的副本。