Понимание нажатия на хеш и конструкцию ||=[]. (сгенерировано в файле 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}||=[]}, $.;
        }
    }
  }
  ...
}

У меня две проблемы:

  1. ||=[], Это | с последующим |=или это или || с последующим =[], Может кто-нибудь рассказать мне, что здесь происходит? (Я предполагаю, что "если хеш пуст, создайте пустой анонимный массив для инициализации хэша", но я изо всех сил пытаюсь увидеть, как это формируется из кода.)
  2. 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) и ссылка на массив

Давайте попробуем разобрать этот шаг за шагом:

  1. Строка используется для заполнения хеша arrayrefs, где arrayrefs содержат номера строк, где $desc регулярные выражения Результирующий %violated хеш будет выглядеть примерно так:

    ( desc1 => [ 1, 5, 7, 10 ], desc2 => [ 2, 3, 4, 6, 8 ] );

  2. push принимает массив в качестве первого аргумента. Переменная $violated{$desc является arrayref, а не массивом, поэтому @{...} используется для разыменования (разыменование является противоположностью ссылки).

  3. Теперь для сложной части. Материал внутри фигурных скобок - просто причудливый способ сказать, что если $violated{$desc} не определяется внутри %violated (проверено с ||), это назначено (=) в пустой массив[]). Думайте об этом как о двух назначениях в одной строке:

    $violated{$desc} = $violated{$desc} || [];

    push @{$violated{$desc}}, $.;

  4. Обратите внимание, что это усложнение обычно не требуется, благодаря функции, называемой autovivification, которая автоматически создает ранее неопределенные ключи внутри хеша с заданным контекстом (в данном случае это ссылка на массив). Единственный случай, когда я могу придумать, где это будет необходимо, это если $violated{$desc} == 0 до.

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