Почему не удается проверить, пуст ли хеш?

Существует много ссылок на то, как проверить, является ли хэш пусто. Я попробовал их все в следующем скрипте:

use strict;
use warnings;
use Data::Dumper;
   $Data::Dumper::Sortkeys = 1;

# Signals come...
my %items = (
    item_1 => {signal_1 => 'up',
               signal_2 => 'down',
               signal_3 => 'up',
              },
    item_2 => {signal_1 => 'down',
              },
    item_3 => {signal_1 => 'up',
               signal_3 => 'down',
               signal_4 => 'down',
               signal_5 => 'down',
              },
  );

# ... and signals go:
delete $items{'item_2'}->{'signal_1'};
# and sometimes all signals are gone from an item:
print Dumper(\%items);
# in that case we would like the signal count to show 0 (zero).
my %signals;
foreach my $item (sort keys %items){
  #$signals{$item} = 0;
  foreach my $signal (sort keys %{$items{$item}}){
    if   (not %{$items{$item}}) {print "HERE\n"; $signals{$item} = 0}
    elsif($items{$item}->{$signal} eq 'up')  {$signals{$item}++}
    elsif($items{$item}->{$signal} eq 'down'){$signals{$item}--}
  }
}
# unfortunately the item disappears completely!
print Dumper(\%signals);

Кажется, итератор полностью пропускает пустой хэш. Мой единственный способ получить правильный результат состоял в том, чтобы инициировать каждый счетчик до нуля (закомментировать) и позволить ему увеличиваться/уменьшаться непустыми хэшами.

Почему это...???


person MeirG    schedule 01.02.2017    source источник
comment
@Toto Я думаю, вопрос в том, почему нет item_2 => 0.   -  person simbabque    schedule 01.02.2017
comment
@simbabque: хорошо, я неправильно понял :(   -  person Toto    schedule 01.02.2017
comment
Если есть X ключей для итерации, то есть X итераций цикла. Да, это применимо, даже когда X равно нулю. Ваш обходной путь на самом деле является правильным способом справиться с ситуацией.   -  person ikegami    schedule 01.02.2017


Ответы (1)


Если в хеше нет ключей, то keys возвращает пустой список (). Когда вы выполняете итерацию с помощью foreach по пустому списку, тело цикла никогда не будет вызвано. Таким образом, ваш print "HERE" никогда не будет достигнут. Это верно.

foreach (()) {
    print "foo";
}

__END__
(no output)

авто-оживление Perl создает для вас значения в хэше, когда вы используете их в первый раз, и значения начинаются как 0, когда вы выполняете с ними математические операции. Вот почему вы можете добавлять и вычитать из них в своем цикле внутри условий.

Чтобы заставить это работать, вы уже сделали правильную вещь со своей закомментированной строкой.

foreach my $signal (sort keys %{$items{$item}}){
    $signals{$item} = 0;
    if ( ...

Теперь вы сначала инициализируете каждый ключ 0. Это делает то же самое, делая это неявно, как описано выше, просто делает это каждый раз.

person simbabque    schedule 01.02.2017