Почему я могу использовать @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 есть несколько советов по печати хэшей.

Другие вопросы по тегам