1

Today I start my perl journey, and now I'm exploring the data type.

My code looks like:

@list=(1,2,3,4,5);
%dict=(1,2,3,4,5);

print "$list[0]\n";         # using [ ] to wrap index
print "$dict{1}\n";         # using { } to wrap key

print "@list[2]\n";
print "%dict{2}\n";

it seems $ + var_name works for both array and hash, but @ + var_name can be used to call an array, meanwhile % + var_name can't be used to call a hash.

Why?

Keith Thompson
  • 254,901
  • 44
  • 429
  • 631
Zen
  • 4,381
  • 5
  • 29
  • 56

2 Answers2

3

@list[2] works because it is a slice of a list.

In Perl 5, a sigil indicates--in a non-technical sense--the context of your expression. Except from some of the non-standard behavior that slices have in a scalar context, the basic thought is that the sigil represents what you want to get out of the expression.

If you want a scalar out of a hash, it's $hash{key}. If you want a scalar out of an array, it's $array[0]. However, Perl allows you to get slices of the aggregates. And that allows you to retrieve more than one value in a compact expression. Slices take a list of indexes. So,

@list = @hash{ qw<key1 key2> };

gives you a list of items from the hash. And,

@list2 = @list[0..3];

gives you the first four items from the array. --> For your case, @list[2] still has a "list" of indexes, it's just that list is the special case of a "list of one".

As scalar and list contexts were rather well defined, and there was no "hash context", it stayed pretty stable at $ for scalar and @ for "lists" and until recently, Perl did not support addressing any variable with %. So neither %hash{@keys} nor %hash{key} had meaning. Now, however, you can dump out pairs of indexes with values by putting the % sigil on the front.

my %hash = qw<a 1 b 2>;
my @list = %hash{ qw<a b> }; # yields ( 'a', 1, 'b', 2 )
my @l2   = %list[0..2];      # yields ( 0, 'a', 1, '1', 2, 'b' )

So, I guess, if you have an older version of Perl, you can't, but if you have 5.20, you can.


But for a completist's sake, slices have a non-intuitive way that they work in a scalar context. Because the standard behavior of putting a list into a scalar context is to count the list, if a slice worked with that behavior:

( $item = @hash{ @keys } ) == scalar @keys;

Which would make the expression:

$item = @hash{ @keys };

no more valuable than:

scalar @keys;

So, Perl seems to treat it like the expression:

$s = ( $hash{$keys[0]}, $hash{$keys[1]}, ... , $hash{$keys[$#keys]} );

And when a comma-delimited list is evaluated in a scalar context, it assigns the last expression. So it really ends up that

$item = @hash{ @keys }; 

is no more valuable than:

$item = $hash{ $keys[-1] };

But it makes writing something like this:

$item = $hash{ source1(), source2(), @array3, $banana, ( map { "$_" } source4()};

slightly easier than writing:

$item = $hash{ [source1(), source2(), @array3, $banana, ( map { "$_" } source4()]->[-1] }

But only slightly.

Axeman
  • 29,660
  • 2
  • 47
  • 102
  • Actually it looks like they have a meaning - `perl -e '%h=(a=>1, b=>2); print join(" ", %h{a,b})'` prints `a 1 b 2`. I'm not sure if this is recent addition to perl though - I'm using perl 5.20 to run it. – svsd Feb 26 '15 at 03:57
  • @skmrx, that actually makes sense, Now that you mention, I've heard that something like that was in the works. I'm glad they made that change. I can throwaway my "hashsubset" library. I'll have to change the text. I wonder if `%array[0,2]` also throws out the indexes as well. – Axeman Feb 26 '15 at 04:43
  • *"In Perl 5, a sigil indicates the context of your expression"* is wrong. An expression can't have a context on its own. For instance, if I write `my $last = @arr[2]` then it is in *scalar* context. – Borodin Feb 26 '15 at 11:32
1

Arrays are interpolated within double quotes, so you see the actual contents of the array printed.

On the other hand, %dict{1} works, but is not interpolated within double quotes. So, something like my %partial_dict = %dict{1,3} is valid and does what you expect i.e. %partial_dict will now have the value (1,2,3,4). But "%dict{1,3}" (in quotes) will still be printed as %dict{1,3}.

Perl Cookbook has some tips on printing hashes.

svsd
  • 1,831
  • 9
  • 14