Может ли undef быть ключом хеша в Perl?

Ответ — нет.

undef не может быть ключом хеша в Perl. Но есть тонкости из-за которых может возникнуть впечатление что может. Подробности ниже.

Что такое хеш

Одна из структур данных, которая существует в языке программирования Perl — это хеш. Хеш это неупорядоченный набор пар значений. Вот пример хеша:

my %h = (
    aa => 1,
    bb => 2,
);

В этом хеше хранится две пары значений. В ключе с именем 'aa' хранится значение 1, а в ключе с именем 'bb' хранится значение 2. Для того чтобы получить эти значения, используют синтаксис $h{aa} и $h{bb}.

Что такое undef

undef — это специальное значение в Perl, которое означает отсутствие значения. Если создать переменную, но не присвоить ей никакое значение, то ее значение будет как раз undef:

▶ Run
#!/usr/bin/perl

use Data::Dumper;

my $var;

print Dumper $var;

Программа выведет на экран текст $VAR1 = undef;.

undef еще можно получить если обратиться к несуществующему элементу массива или к несуществующему ключу в хеше. Можно явно присвоить undef переменной: $var = undef;.

Ошибочное использование 1

Вот пример программы из которой кажется что undef может быть ключом хеша:

▶ Run
#!/usr/bin/perl

my %h = (
    undef => 'asdf',
);

print $h{undef};

Программа выводит на экран текст asdf. Т.е. как будто мы создали в хеше ключ undef, а потом достали значение по этому ключу. Но это не так. В этом примере значение хранится в ключе 'undef', т.е. строка 'undef', а не настоящий undef.

Так происходит из-за двух особенностей.

При создании хеша мы создали в нем пару ключ-значение с помощью кода undef => 'asdf',. В этом коде используется оператор =>. Особенность этого оператор в том что в некоторых ситуациях он может воспринимать то что находится слева как строку. Он как будто бы заключает то что находится слева от => в кавычки. undef => 'asdf', это на самом деле 'undef' => 'asdf',.

Вторая особенность — это то как мы достаем значение из хеша по ключу. Мы используем синтаксис $h{undef}. И тут Perl считает что то что находится в фигурных скобках — это строка. То что мы тут написали это то же самое что и $h{'undef'}.

Можно убедится что это действительно так если запустить скрипт, подключив специальный модуль, который вместо выполнения кода, показывает как Perl понимает этот код. perl -MO=Deparse script.pl. Вот вывод:

my(%h) = ('undef', 'asdf');
print $h{'undef'};
script.pl syntax OK

Ошибочное использование 2

Вот еще один пример кода из которого ошибочно кажется что undef может быть ключом хеша. Уж тут-то мы используем настоящий undef, а не строчку 'undef':

▶ Run
#!/usr/bin/perl

my $var = undef;

my %h = (
    $var => 'asdf',
);

print $h{$var};

Программа выводит на экран текст asdf. Т.е. действительно кажется что мы мы создали значение в хеше по ключу undef.

Но на самом деле, мы разместили значение в ключе '' (пустая строка). Если дописать в конец этой программы строки use Data::Dumper и warn Dumper \%h;, то после запуска на экране будет видно как на самом деле выглядит хеш:

$VAR1 = {
          '' => 'asdf'
        };

Переменная $var содержит в себе значение undef, но при использовании в $var => 'asdf', и $h{$var} undef заменяется на пустую строку ''.

Если добавить в код use strict; и use warnings; (что практически всегда стоит делать), то в выводе программы будет видно что Perl предупреждает о таком использовании:

Use of uninitialized value $var in list assignment at script.pl line 8.
Use of uninitialized value $var in hash element at script.pl line 12.

Резюме

undef не может быть значением ключа в Perl хеше. Ключи в Perl хеше — это всегда строки. (Уточним только, что пустая строка '' тоже может быть ключом). А значения в хеше могут быть совершенно любыми и там без проблем может быть undef.

Другие статьи

Комментарии