为什么$ foo - > {bar} autovivify但%$ foo没有?

Eug*_*kov 3 perl reference autovivification

我有以下代码:

$headers;
some_sub( %$headers );
Run Code Online (Sandbox Code Playgroud)

当我打电话时,some_sub我得到一个错误:

不能使用未定义的值作为HASH参考...

但类似的代码不会产生错误:

$headers->{ x };
Run Code Online (Sandbox Code Playgroud)

为什么自动复制在第一个示例中的工作方式与在第二个示例中的工作方式不同?

UPD

我注意到@ThisSuitIsBlackNot.我真的问:

为什么我的$ h; $ h - > {foo}的作品和我的$ h; %$ h没有

UPD
真正的代码:

my $email =  Email::Simple->create(()
    ,header =>  [()
        ,To             =>  $address
        ,From           =>  $cnf->{ from }
        ,Subject        =>  $subject
        ,'Content-Type' =>  'text/html; charset="utf8"'
        ,%$headers
    ]
    ,body => $body
);
Run Code Online (Sandbox Code Playgroud)

zdi*_*dim 6

注意   问题中添加的代码说明了为什么不进行自动生存。

简短说明   您的子项使用一个列表(哈希),该列表具有一个匿名数组作为元素–并%$headers埋在该数组中。 标称别名是匿名数组,因此不需要%$headers进行修改。因此,不会进行自动生存,并且由于在未定义的引用上尝试取消引用,因此会出现下面描述的致命运行时错误。


%$ref左值上下文中使用时,a自动存活。这可能会在子调用中发生,请参见下文。

您显示的错误是由于使用了未定义的引用。例如,语句

my %hash = %{ $ref };
Run Code Online (Sandbox Code Playgroud)

尝试从存储在其中的内存位置复制哈希$ref并将其分配给%hash。该符号%hash是在编译时创建的,但是如果在时未找到散列$ref或中没有任何内容$ref,则会出现错误。这里没有自动生存。具有use strict效果

perl -wE'use strict; my $h; my %h = %$h; say $h'
Run Code Online (Sandbox Code Playgroud)

这会引发致命的运行时错误

不能在-e第1行使用未定义的值作为HASH引用。

eval-ed 何时生存

perl -wE'use strict; my $h; my %h = eval { %$h }; say $h; say "hi"'
Run Code Online (Sandbox Code Playgroud)

它显示有关“ 未初始化的值 ” 的警告,空行,然后显示hi。没有哈希。

但是,当在子例程调用中用作参数时,它会自动生存

perl -wE'use strict; sub tt { 1 }; my $h; tt( %$h ); say $h'
Run Code Online (Sandbox Code Playgroud)

因为这将打印行HASH(0x257cd48),而没有警告或错误。

当在左值上下文中使用被取消引用的对象时,会发生自生存,这意味着它需要可修改。在子例程调用中,其原因是函数的参数被别名化,@_因此必须可以对其进行修改。相同的别名需求使其在foreach循环中发生,同时keys重置哈希迭代器。请参阅这篇文章这篇文章这篇文章

感谢ThisSuitIsBlackNot提供的解释和链接。

在您的情况下,%$ref将其作为匿名数组的元素传递,因此不会被别名(arrayref本身就是别名)。因此,自动生存无法发挥作用,您会收到该错误。


关于术语自我生存

在Perl中,存储位置(左值)会根据需要自发生成自身,包括创建任何硬参考值以指向下一个存储级别。该分配$a[5][5][5][5][5] = "quintet"可能会创建五个标量存储位置,外加指向四个新匿名数组(以保存最后四个标量位置)的四个引用(在前四个标量位置)。但是,自动生存的关键是您不必为此担心。

另请参见,例如,Effective Pearler文章

  • 实际上,`%$ foo` *确实会触发自动生存,* if *在l值上下文中使用:`perl -Mstrict -MDevel :: Peek -wE'my $ h; 1,代表%$ h;转储$ h'(SV = PVHV表示它是一个hashref) (2认同)

mob*_*mob 5

%$hash 传递给sub时绝对会自动生成.

$ perl -Mstrict -wE'my $foo; say $foo // "undef"'
undef

$ perl -Mstrict -wE'sub f { } my $bar; f(%$bar); say $bar // "undef"'
HASH(0x10b50e0)
Run Code Online (Sandbox Code Playgroud)

错误消息来自其他正在进行的操作some_sub,可能是来自的不正确的分配@_.

  • “`%$ hash`在传递给函数(用户或内置函数)时绝对可以自动生存”。对于某些运算符(例如,“ keys”),但对于其他运算符(例如,“ length”),则为true。 (2认同)