注意 添加到问题中的代码演示了为什么不会发生自动生存。
Short 你的 sub 接受一个列表(散列),它有一个匿名数组作为元素——并%$headers
被埋在那个数组中。标量别名是匿名数组
,因此不需要%$headers
可修改。因此不会发生自动激活,并且您会收到下面描述的致命运行时错误,因为在未定义的引用上尝试取消引用。
在左值上下文中%$ref
使用时自动激活。这可能发生在子调用中,见下文。
您显示的错误是由于使用了未定义的引用。例如,声明
my %hash = %{ $ref };
尝试从存储的内存位置复制哈希$ref
并将其分配给%hash
. 该符号%hash
是在编译时创建的,但如果在 处没有找到散列$ref
或者在 中没有任何东西$ref
,我们会得到一个错误。这里不会发生自动存活。use strict
生效_
perl -wE'use strict; my $h; my %h = %$h; say $h'
这会引发致命的运行时错误
不能在 -e 第 1 行使用未定义的值作为 HASH 引用。
当eval
-ed 生存下来
perl -wE'use strict; my $h; my %h = eval { %$h }; say $h; say "hi"'
它打印一个关于“未初始化值”的警告,一个空行,然后hi
. 没有哈希。
但是,当用作子例程调用中的参数时,它会自动激活
perl -wE'use strict; sub tt { 1 }; my $h; tt( %$h ); say $h'
因为这会打印 line HASH(0x257cd48)
,没有警告或错误。
当在左值上下文中使用取消引用的对象时会发生自动激活,这意味着它需要是可修改的。在子例程调用中,这样做的原因是函数的参数有别名,@_
因此必须可以修改它们。相同的别名需要使其在foreach
循环中发生,同时keys
重置哈希迭代器。请参阅这篇文章、这篇文章和这篇文章。
感谢ThisSuitIsBlackNot的解释和链接。
在您的情况下,%$ref
作为匿名数组的元素传递,因此没有别名(arrayref 本身是)。所以 autovivication 不会启动,你会得到那个错误。
从perlglossary论自动生存
在 Perl 中,存储位置(左值)会根据需要自行生成,包括创建任何硬引用值以指向下一级存储。该分配$a[5][5][5][5][5] = "quintet"
可能会创建五个标量存储位置,以及指向四个新匿名数组(用于保存最后四个标量位置)的四个引用(在前四个标量位置中)。但是自动复活的重点是您不必担心它。
也可以看看,例如,来自 Effective Perler 的一篇文章