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?
@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.