Почему я могу использовать @list для вызова массива, но не могу использовать%dict для вызова хэша в perl?
Сегодня я начинаю свое путешествие по Perl, и теперь я изучаю тип данных.
Мой код выглядит так:
@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";
похоже на то $ + var_name
работает как для массива, так и для хэша, но @ + var_name
может быть использован для вызова массива, в то же время % + var_name
нельзя использовать для вызова хеша.
Зачем?
2 ответа
@list[2]
работает, потому что это кусок списка.
В Perl 5 символ указывает - в нетехническом смысле - на контекст вашего выражения. За исключением некоторого нестандартного поведения срезов в скалярном контексте, основная мысль состоит в том, что сигил представляет то, что вы хотите получить из выражения.
Если вы хотите скаляр из хеша, это $hash{key}
, Если вы хотите скаляр из массива, это $array[0]
, Тем не менее, Perl позволяет получать фрагменты агрегатов. И это позволяет вам получить более одного значения в компактном выражении. Ломтики занимают список индексов. Так,
@list = @hash{ qw<key1 key2> };
дает вам список элементов из хэша. А также,
@list2 = @list[0..3];
дает вам первые четыре элемента из массива. -> Для вашего случая, @list[2]
все еще имеет "список" индексов, просто этот список является частным случаем "списка одного".
Поскольку скалярные и списочные контексты были довольно хорошо определены, и не было никакого "хэш-контекста", он оставался довольно стабильным в $
для скалярных и @
для "списков" и до недавнего времени Perl не поддерживал адресацию любой переменной с помощью %
, Так что ни %hash{@keys}
ни %hash{key}
имел значение. Однако теперь вы можете вывести пары индексов со значениями, поставив %
знак на фронте.
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' )
Так что, я думаю, если у вас есть более старая версия Perl, вы не можете, но если у вас есть 5.20, вы можете.
Но ради завершенности, срезы имеют неинтуитивный способ работы в скалярном контексте. Поскольку стандартное поведение помещения списка в скалярный контекст - это подсчет списка, если срез работал с таким поведением:
( $item = @hash{ @keys } ) == scalar @keys;
Что бы сделать выражение:
$item = @hash{ @keys };
не более ценный, чем:
scalar @keys;
Итак, Perl, похоже, воспринимает это как выражение:
$s = ( $hash{$keys[0]}, $hash{$keys[1]}, ... , $hash{$keys[$#keys]} );
И когда список с разделителями-запятыми оценивается в скалярном контексте, он назначает последнее выражение. Так что это действительно заканчивается тем, что
$item = @hash{ @keys };
не более ценен, чем:
$item = $hash{ $keys[-1] };
Но это заставляет писать что-то вроде этого:
$item = $hash{ source1(), source2(), @array3, $banana, ( map { "$_" } source4()};
немного проще, чем писать:
$item = $hash{ [source1(), source2(), @array3, $banana, ( map { "$_" } source4()]->[-1] }
Но только немного.
Массивы интерполируются в двойных кавычках, поэтому вы видите фактическое содержимое напечатанного массива.
С другой стороны, %dict{1}
работает, но не интерполируется в двойных кавычках. Итак, что-то вроде my %partial_dict = %dict{1,3}
действует и делает то, что вы ожидаете, т.е. %partial_dict
теперь будет иметь значение (1,2,3,4)
, Но "%dict{1,3}"
(в кавычках) будет по-прежнему печататься как %dict{1,3}
,
В Perl Cookbook есть несколько советов по печати хэшей.