Должны ли хеши Perl всегда содержать значения? - PullRequest
7 голосов
/ 27 мая 2009

У меня был более ранний вопрос, который получил следующий ответ от известного эксперта по Perl, автора Perl и тренера по Perl Брайана Д. Фоя:

[Если] вы ищете фиксированную последовательность символов в конце каждого имени файла. Вы хотите знать, входит ли эта фиксированная последовательность в список последовательностей, которые вас интересуют. Сохраните все расширения в хэше и посмотрите на него:
    my( $extension ) = $filename =~ m/\.([^.]+)$/;
    if( exists $hash{$extension} ) { ... }
Вам не нужно создавать регулярное выражение, и вам не нужно проходить через несколько возможных чередований регулярных выражений, чтобы проверить каждое расширение, которое вы должны исследовать.

Спасибо за совет, Брайан.

То, что я сейчас хочу знать, это то, что является лучшей практикой в ​​случае, подобном описанному выше. Стоит ли определять только ключи, и это все, что мне нужно для достижения того, что описано выше, или всегда следует также определять значение?

Ответы [ 6 ]

5 голосов
/ 28 мая 2009

Обычно предпочтительно устанавливать определенное значение для каждого ключа. Идиоматическое значение (когда вас не волнует значение) равно 1.

my %hash = map { $_ => 1 } @array;

Делая это таким образом, код использует хеш немного проще, потому что вы можете использовать $hash{key} в качестве логического значения. Если значение может быть неопределенным, вам нужно использовать более подробный exists $hash{key}.

Тем не менее, бывают ситуации, когда желательно значение undef. Например: представьте, что вы анализируете заголовочные файлы C для извлечения символов препроцессора. Было бы логично хранить их в хэше пар имя => значение.

#define FOO 1
#define BAR

В Perl это будет соответствовать:

my %symbols = ( FOO => 1, BAR => undef);

В C a #define определяет символ , а не значение - «определено» в C отображается как «существует» в Perl.

4 голосов
/ 27 мая 2009

Вы не можете создать хеш-ключ без значения. Значение может быть undef, но оно будет там. Как еще вы построите хеш. Или был ваш вопрос относительно того, может ли значение быть неопределенным? В этом случае я бы сказал, что значение, которое вы там храните (undef, 1, 0 ...), полностью зависит от вас. Если многие люди используют его, вы, вероятно, захотите сохранить какое-то истинное значение, хотя кто-то другой использует if ($ hash {$ extension}) {...} вместо существования, потому что они не обращали внимания. *

3 голосов
/ 28 мая 2009

Как уже говорили другие, идиоматическое решение для хэш-набора (хеш-код, который содержит только ключи, а не значения) заключается в использовании 1 в качестве значения, поскольку это облегчает тестирование на существование. Тем не менее, есть кое-что, что нужно сказать для использования undef в качестве значения. Это заставит пользователей проверять существование с exists, что немного быстрее. Конечно, вы можете проверить существование с помощью exists, даже если значение равно 1, и избежать неизбежных ошибок пользователей, которые забывают использовать exists.

3 голосов
/ 27 мая 2009

undef - это значение.

Конечно, подобные вещи всегда зависят от того, что вы делаете в данный момент. Но $foo{bar} - это просто переменная, подобная $bar, и я не вижу причин, по которым каждый из них не должен быть undef время от времени.

PS: Вот почему существует exists.

1 голос
/ 30 мая 2009

Использование undef в качестве значения в хэше более эффективно, чем хранение 1.

1 голос
/ 29 мая 2009

Хранение '1' в сет-хэше считается опасным

Я знаю, используя Считается вредным считается вредным , но это плохо; почти так же плохо, как безудержное использование goto.

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

Допустим, у нас есть процесс-демон, который обеспечивает внутренний контроль запасов для магазина, который продает виджеты.

my @items = qw(
    widget
    thingy
    whozit
    whatsit
);

my @items_in_stock = qw(
    widget
    thingy
);

my %in_stock;
my @in_stock(@items_in_stock) = (1) x @items_in_stock;  #initialize all keys to 1

sub Process_Request {
    my $request = shift;

    if( $request eq REORDER ) {
        Reorder_Items(\@items, \%in_stock);
    }
    else { 
        Error_Response( ILLEGAL_REQUEST );
    }
}

sub Reorder_Items{
   my $items = shift;
   my $in_stock =  shift;

   # Order items we do not have in-stock.
   for my $item ( @$items ) {

       Reorder_Item( $item ) 
           if not exists $in_stock->{$item};
   }

}

Инструмент отличный, он автоматически сохраняет товары на складе. Очень хорошо. Теперь босс просит автоматически сгенерированные каталоги товаров на складе. Поэтому мы модифицируем Process_Request() и добавляем генерацию каталога.

sub Process_Request {
    my $request = shift;

    if( $request eq REORDER ) {
        Reorder_Items(\@items, \%in_stock);
    }
    if( $request eq CATALOG ) {
        Build_Catalog(\@items, \%in_stock);
    }
    else { 
        Error_Response( ILLEGAL_REQUEST );
    }
}

sub Build_Catalog {
    my $items = shift;
    my $in_stock = shift;

    my $catalog_response = '';
    foreach my $item ( @$items ) {
        $catalog_response .= Catalog_Item($item)
            if $in_stock->{$item};
    }

    return $catalog_response;
} 

В тестировании Build_Catalog () работает нормально. Ура, мы живем с приложением.

К сожалению. По какой-то причине ничего не заказывается, у компании нет на складе всего .

Подпрограмма Build_Catalog() добавляет ключи к %in_stock, поэтому Reorder_Items() теперь видит все как в наличии и никогда не делает заказ.

Использование Hash :: Util lock_hash может помочь предотвратить случайное изменение хеша. Если бы мы заблокировали %in_stock перед вызовом 'Build_Catalog ()', мы получили бы фатальную ошибку и никогда бы не сработали с ошибкой.

Таким образом, лучше всего проверить наличие ключей, а не истинность ваших значений set-hash. Если вы используете в качестве обозначения наличие, не устанавливайте значения «1», потому что это замаскирует ошибки и затруднит их отслеживание. Использование lock_hash может помочь решить эти проблемы.

Если вы должны проверить правильность значений, сделайте это в в каждом случае.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...