问题
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
);
回答1:
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 Pearler
回答2:
%$hash
absolutely does autovivify when passed to a sub.
$ perl -Mstrict -wE'my $foo; say $foo // "undef"'
undef
$ perl -Mstrict -wE'sub f { } my $bar; f(%$bar); say $bar // "undef"'
HASH(0x10b50e0)
The error message comes from something else going on in some_sub
, perhaps an improper assignment from @_
.
来源:https://stackoverflow.com/questions/41400902/why-does-foo-bar-autovivify-but-foo-doesnt