Понимание нажатия на хеш и конструкцию ||=[]. (сгенерировано в файле steamplate.t)
Я заново знакомлюсь с Perl, и только что использовал module-starter
инициализировать новый проект. Я сейчас пытаюсь понять сгенерированный код. Все хорошо, за исключением следующей строки:
sub not_in_file_ok {
my ($filename, %regex) = @_;
open( my $fh, '<', $filename )
or die "couldn't open $filename for reading: $!";
my %violated;
while (my $line = <$fh>) {
while (my ($desc, $regex) = each %regex) {
if ($line =~ $regex) {
##I'm having problems here
push @{$violated{$desc}||=[]}, $.;
}
}
}
...
}
У меня две проблемы:
||=[]
, Это|
с последующим|=
или это или||
с последующим=[]
, Может кто-нибудь рассказать мне, что здесь происходит? (Я предполагаю, что "если хеш пуст, создайте пустой анонимный массив для инициализации хэша", но я изо всех сил пытаюсь увидеть, как это формируется из кода.)push @{$violated{$desc}}, $.
Я понимаю, что это означает "назначить номер строки для ключа$desc
для хэша%violated
, Но из кода, который я прочитал, "посмотрите значение ключаdesc
из$violated{$desc}
($violated{$desc}
часть), затем используйте это значение в качестве символической ссылки на массив (@{$value}
часть), затем вставьте номер строки в этот массив ". Я не вижу, как согласовать эти два представления.
Я думаю, что мне есть чему поучиться в этой строке кода - может ли кто-нибудь помочь мне, пройдя через это?
2 ответа
||=
: это оператор присваивания. пример$a ||= $b; # corresponds to $a = $a || $b;
увидеть
man perlop
, В вашем примере$a ||= []; # corresponds to $a = $a || [];
то есть: если левый операнд определен ни к чему, в противном случае присваивается пустая ссылка на массив
%violated
содержит ссылку на массив для каждого значения. Вы можете видеть это так:my $array_ref = $violated{$desc}; push @{array_ref}, $.;
Написано более многословно:
if (! $violated{$desc} ) {
$violated{$desc} = [];
}
my $array_ref = $violated{$desc};
push @{ $array_ref }, $.;
РЕДАКТИРОВАТЬ
Массивы и ссылки на массивы
массив, построенный с
()
и содержит динамический упорядоченный список элементов (в Perl массивы могут расти динамически)ссылка на массив - это ссылка на массив (более или менее указатель без арифметики указателя). Вы можете создать и массив ссылки с
[]
пример
my @a = ( 1, 2, 3);
# $a[0] will contain 1
my $array_ref = [ 10, 11, 12 ];
# array_ref is a _pointer_ to an array containing 10, 11 and 12
Чтобы получить доступ к ссылке на массив, вам нужно разыменовать его:
@{ $array_ref };
my @array = @{ $array_ref }; # is valid
Вы можете получить доступ { $array_ref}
как массив
${ $array_ref }[0]
Теперь вернемся к вашему вопросу в комментарии: %violated
хеш со следующими парами ключ-значение: строка ($desc) и ссылка на массив
Давайте попробуем разобрать этот шаг за шагом:
Строка используется для заполнения хеша arrayrefs, где arrayrefs содержат номера строк, где
$desc
регулярные выражения Результирующий%violated
хеш будет выглядеть примерно так:( desc1 => [ 1, 5, 7, 10 ], desc2 => [ 2, 3, 4, 6, 8 ] );
push
принимает массив в качестве первого аргумента. Переменная$violated{$desc
является arrayref, а не массивом, поэтому@{...}
используется для разыменования (разыменование является противоположностью ссылки).Теперь для сложной части. Материал внутри фигурных скобок - просто причудливый способ сказать, что если
$violated{$desc}
не определяется внутри%violated
(проверено с||
), это назначено (=
) в пустой массив[]
). Думайте об этом как о двух назначениях в одной строке:$violated{$desc} = $violated{$desc} || [];
push @{$violated{$desc}}, $.;
Обратите внимание, что это усложнение обычно не требуется, благодаря функции, называемой autovivification, которая автоматически создает ранее неопределенные ключи внутри хеша с заданным контекстом (в данном случае это ссылка на массив). Единственный случай, когда я могу придумать, где это будет необходимо, это если
$violated{$desc} == 0
до.