开发者

Why does Perl treat a hash element as list context at declaration?

Given this code:

#!/usr/bin/perl -w

use strict;
use warnings;

sub foo {
    return wantarray ? () : "value1";
}

my $hash = {
    key1 => foo(),
    key2 => 'value2'
};

use Data::Dumper;
print Dumper($hash);

I get the following output:

$VAR1 = {
  'key1' => 'key2',
  'value2' => undef
};

When I would expect:

$VAR1 = {
  'key1' => 'value1',
  'key2' => 'value2'
};

I understand that a hash is kind-of an even-sized array (as evidenced by the "Odd number of elemen开发者_开发问答ts in hash assignment" warning I'm getting) but a hash element can only be a scalar, why would the compiler be giving it array context?

I found this using the param function of the CGI module when assigning directly to a hash. The foo() function above was a call to CGI::param('mistyped_url_param') which was returning an empty array, destroying (rotating?) the hash structure.


The fat comma isn't a special hash assignment operator. It just a piece of syntactic sugar that means "auto-quote the previous thing"

So:

my $hash = {
    key1 => foo(),
    key2 => 'value2'
};

Means:

my $hash = {
    'key1', foo(), 'key2', 'value2'
};

… which is a list and, as willert says:

every expression in a list is evaluated in list context. You can get around this by calling scalar foo()


An anonymous hash constructor supplies list context to the things inside it because it expects a list of keys and values. It's that way because that's the way it is. We don't have a way to represent a Perl hash in code, so you have to use a list where we alternate keys and values. The => notation helps us visually, but performs no magic that helps Perl figure out hashy sorts of things.

Current context propogates to subroutine calls, etc just like it does in any other situation.

This allows you to build hashes with list operations:

 my $hash = { 
      a => 'A',  
      map( uc, 'd' .. 'f' ),
      return_list( @args ), 
      z => 'Z' 
      };

If you need something to be in scalar context, just say so using scalar:

 my $hash = { 
      a => 'A',  
      map( uc, 'd' .. 'f' ),
      'g' => scalar return_item( @args ), 
      z => 'Z' 
      };
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜