Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/codeigniter/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Perl 哈希键行为_Perl_Autovivification - Fatal编程技术网

Perl 哈希键行为

Perl 哈希键行为,perl,autovivification,Perl,Autovivification,输出 perl -Mstrict -wlE 'my %h; say grep 0, $h{poluted}; say keys %h' 及 没有输出 我想知道为什么输出不同?别名 在Perl的循环构造map、grep和for中,$\ucode>变量被别名化到每个当前项。虽然$\uuu可能是只读的,但它始终表示有效的标量值 例如,以下代码失效: perl -Mstrict -wlE 'my %h; say grep 0, my @r= $h{poluted}; say keys %h' 但这是

输出

perl -Mstrict -wlE 'my %h; say grep 0, $h{poluted}; say keys %h'

没有输出

我想知道为什么输出不同?

别名 在Perl的循环构造
map
grep
for
中,
$\ucode>变量被别名化到每个当前项。虽然
$\uuu
可能是只读的,但它始终表示有效的标量值

例如,以下代码失效:

perl -Mstrict -wlE 'my %h; say grep 0, my @r= $h{poluted}; say keys %h'
但这是可行的:

$_ = 1 for 1, 2, 3;  # constants are read-only
请注意,指定执行复制,但别名将名称与现有标量相关联

两个
undef
值 Perl有两种
unde

  • 标量可以设置为表示
    undef
    。例如:

    my @nums = (1, 2, 3);
    $_ = 1 for @nums;  # @nums isn't read-only
    
  • 一种特殊的全局唯一标量,表示只读
    undef
    值,例如,在右值上下文中访问未初始化的数组索引时返回。在Perl API中,这是
    &PL\u sv\u unde
    。您可以获取对此值的引用,例如
    \unde
    ,并可以为其别名变量

访问散列值的两种方法 在内部,通过
hv\u fetch
hv\u fetch\u ent
获取散列项。作为参数,两者都使用散列、密钥和标志,告诉它们访问是否为只读

如果这是只读访问且元素不存在,将返回一个空指针,它在Perl空间中显示为
unde
值。此
undef
值未连接到哈希。因此,
不存在$hash{foo}
意味着
未定义$hash{foo}

但如果它不是只读的,并且元素不存在,则会创建一个新条目,然后返回该条目。但是,在通过赋值将该条目设置为另一个值之前,该条目最初是未定义的

那么,为什么问题中的代码不能按预期工作呢? 循环构造的参数列表的别名为
$\uu
。如果列表中的表达式是常量或子例程,则不会发生任何异常。但当它们是可变访问时,则意味着读写访问

因此,为了获得
$h{policted}
的值,Perl显然以读写模式进行访问。如果我们看一下这个表达式的操作码,我们实际上看到:

grep 0, $h{polluted}
3个推码
4 gv[*h]s
5 rv2hv sKR/1
6常数[PV“污染”]s/裸
7直升机sKM/2#a[t2]vK
常数[IV 0]s
转到9
M
代表
MOD
,表示左值/读写访问

为什么这种行为“有意义”
for
-循环中,将
$作为当前元素的别名非常有用。在
map
grep
中,这是一种避免复制整个标量的性能攻击。别名要便宜得多,因为这只意味着一个指针的副本。

对于好奇的人来说,可能值得一提的是,可以通过运行类似于
$perl-MO=concrete,-exec-E…
的操作码来获得。pod页面中的语法文档我仍然不清楚为什么
grep
总是访问它的参数r/w。用户定义的子例程并非如此,请参见:
perl-le'sub mod{$\[0]=“modified”}sub nomod{$\[0]}sub refd:lvalue{$\[0]}mod($h{created});nomod({h})$v=refd($h{roref});refd($h{rwref})=1;打印键(%h)
它打印:
created\nrwref
@user2719058在所有这些情况下,散列作为
helem sKM/LVDEFER,2
访问。我不知道这意味着什么,但它似乎是另一个Performance Hack.tnx,因此
grep 0,@[$h{poluted}]}
应该用来防止散列污染。@amon好吧,我想它可以让Perl检测参数别名是否被子例程修改,并推断子例程是否提供左值上下文。我仍然想知道为什么这不适用于
grep
my $foo;  # is this kind of undef
$foo = 1; # isn't undef any more
grep 0, $h{polluted}
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