为什么 $foo->{bar} 自动激活而 %$foo 没有? [英] Why does $foo->{bar} autovivify but %$foo doesn't?

查看:30
本文介绍了为什么 $foo->{bar} 自动激活而 %$foo 没有?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有以下代码:

$headers;some_sub(%$headers);

当我调用 some_sub 时出现错误:

<块引用>

不能在...处使用未定义的值作为 HASH 引用

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

$headers->{ x };

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

UPD

我由 @ThisSuitIsBlackNot 指出.我真的想问:

<块引用>

为什么我的 $h;$h->{foo} 有效,我的 $h;%$h 没有

UPD
真正的代码:

my $email = Email::Simple->create(标题 =>[到 =>$地址,从 =>$cnf->{ from },主题 =>$主题,'内容类型' =>'文本/html;字符集="utf8"',%$标题,],身体 =>$body);

解决方案

注意  添加到问题中的代码说明了为什么不会发生自动激活.

 你的子接受一个列表(哈希),它有一个匿名数组作为元素–并且 %$headers 被埋在该数组中.它是 anon 数组这是别名为的标量,因此不需要 %$headers 是可修改的.因此不会发生自动激活,并且您会收到下面描述的致命运行时错误,因为尝试对未定义的引用进行解引用.

<小时>

A %$ref左值上下文中使用时自动激活.这可能发生在子调用中,见下文.

您显示的错误是由于使用了未定义的引用.例如,声明

my %hash = %{ $ref };

尝试从存储在 $ref 中的内存位置复制一个哈希值并将其分配给 %hash.符号 %hash 是在编译时创建的,但是如果在 $ref 处没有找到哈希值,或者 $ref 中没有任何内容,我们得到一个错误.这里没有自动激活.use strict 生效

perl -wE'use strict;我的 $h;我的 %h = %$h;说 $h'

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

<前>不能在 -e 第 1 行使用未定义的值作为 HASH 引用.

eval-ed 存活

perl -wE'use strict;我的 $h;我的 %h = eval { %$h };说 $h;打招呼"'

它打印一个关于未初始化值"的警告,一个空行,然后是hi.没有哈希.

但是,当在子程序调用中用作参数时,它会自动激活

perl -wE'use strict;子 tt { 1 };我的 $h;tt(%$h);说 $h'

因为这会打印行 HASH(0x257cd48),没有警告或错误.

当在左值上下文中使用解除引用的对象时,就会发生自动激活,这意味着它需要是可修改的.在子程序调用中,这样做的原因是函数的参数在 @_ 中有别名,因此必须可以修改它们.同样的别名需求使它发生在 foreach 循环中,而 keys 重置哈希迭代器.请参阅这篇文章这篇文章这篇文章.

感谢 ThisSuitIsBlackNot 的解释和链接.

在您的情况下, %$ref 作为匿名数组的元素传递,因此没有别名(arrayref 本身是).所以 autovivication 不会启动,你会得到那个错误.

<小时>

关于 autovivification 来自 perlglossary

<块引用>

在 Perl 中,存储位置(左值)会根据需要自发生成,包括创建任何硬引用值以指向下一级存储.赋值 $a[5][5][5][5][5] = "quintet" 可能创建五个标量存储位置,加上四个引用(在前四个标量位置)指向四个新的匿名数组(保存最后四个标量位置).但是自动激活的重点是你不必担心它.

另请参阅,例如,来自 Effective Perler 的文章

I have the following code:

$headers;
some_sub( %$headers );

When I call some_sub I get an error:

Can't use an undefined value as a HASH reference at ...

But similar code does not produce an error:

$headers->{ x };

Why doesn't autovivification work the same way in the first example as it does in the second?

UPD

I noted by @ThisSuitIsBlackNot. I really ask:

why my $h; $h->{foo} works and my $h; %$h doesn't

UPD
The real code:

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

解决方案

Note   Code added to the question demostrates why autovivification doesn't happen.

Short   Your sub takes a list (hash) which has an anonymous array as an element – and %$headers is buried in that array. It is the anon array that is the scalar aliased to, thus there is no requirement for %$headers to be modifiable. Thus no autovivification happens, and you get the fatal runtime error described below, as dereferencing is attempted on an undefined reference.


A %$ref autovivifies when used in lvalue context. This may happen in a sub call, see below.

The error you show is due to the use of an undefined reference. For example, the statement

my %hash = %{ $ref };

attempts to copy a hash from the memory location stored in $ref and assign it to %hash. The symbol %hash is created at compile time, but if no hash is found at $ref or if there is nothing in $ref, we get an error. No autovivification happens here. With use strict in effect

perl -wE'use strict; my $h; my %h = %$h; say $h'

this throws the fatal runtime error

Can't use an undefined value as a HASH reference at -e line 1.

When eval-ed to survive that

perl -wE'use strict; my $h; my %h = eval { %$h }; say $h; say "hi"'

it prints a warning about "uninitialized value", an empty line, and then hi. No hash.

However, when used as an argument in a subroutine call it autovivifies

perl -wE'use strict; sub tt { 1 }; my $h; tt( %$h ); say $h'

as this prints the line HASH(0x257cd48), without warnings or errors.

The autovivification happens when a dereferenced object is used in lvalue context, which means that it needs to be modifiable. In a subroutine call the reason for this is that arguments to a function are aliased in @_ so it must be possible to modify them. The same aliasing need makes it happen in a foreach loop, while keys resets the hash iterator. See this post and this post and this post.

Thanks to ThisSuitIsBlackNot for explanation and links.

In your case the %$ref is passed as an element of an anonymous array, and is thus not aliased (the arrayref itself is). So autovivication does not kick in and you get that error.


On autovivification from perlglossary

In Perl, storage locations (lvalues) spontaneously generate themselves as needed, including the creation of any hard reference values to point to the next level of storage. The assignment $a[5][5][5][5][5] = "quintet" potentially creates five scalar storage locations, plus four references (in the first four scalar locations) pointing to four new anonymous arrays (to hold the last four scalar locations). But the point of autovivification is that you don’t have to worry about it.

Also see, for example, an article from Effective Perler

这篇关于为什么 $foo->{bar} 自动激活而 %$foo 没有?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆