Я должен проверить хеш Perl элемента хеша такой как $Table{$key1}{$key2}
существовать и быть определенным. Вот то, что я делаю. (Я понятия не имею $key1
даже существует),
if
((defined $Table{$key1}) &&
(exists $Table{$key1}) &&
(defined $Table{$key1}{$key2}) &&
(exists $Table{$key1}{$key2}))
{
#do whatever
}
Существует ли более легкий и более чистый способ сделать это?
Сначала проверьте наличие, затем определенность. (Значение может существовать без определения, но не может быть определено, если оно не существует.) Вы должны протестировать промежуточные уровни с помощью exists
, чтобы предотвратить непреднамеренное автовивификацию. Для последнего уровня вам нужно только вызвать определенный
. Когда слоев не так много, легко кодировать напрямую:
if (exists $hash{a} && defined $hash{a}{b}) {...}
Это становится неудобно, если слоев много:
if (exists $hash{a} && exists $hash{a}{b} && exists $hash{a}{b}{c} ...) {...}
В этом случае вы можете написать версию , определенную
, которая не autovivify промежуточные значения:
sub safe_defined {
my $h = shift;
foreach my $k (@_) {
if (ref $h eq ref {}) {
return unless exists $h->{$k};
$h = $h->{$k};
}
else {
return;
}
}
return defined $h;
}
Вы используете его следующим образом:
if (safe_defined(\%hash, qw(a b c))) {
say $hash{a}{b}{c};
}
Примечание: эта версия функции ограничена.
Настоящая общая версия оставлена читателю в качестве упражнения. ;)
Следующее короче и защитит от автовивификации:
if (exists $table{$key1} and defined $table{$key1}{$key2}) {...}
Другие проверки в вашем коде не нужны.
Вам не нужно проверять каждый уровень иерархии: вы можете просто выбрать ценность, которая вам небезразлична. существует
не проверяет определенность, только если слот в хэше существует (он может существовать с неопределенным значением), поэтому, если вам важно, чтобы значение было определено, вам нужно будет вызвать определен
, а не существует.Если значение не определено, оно оценивается в логическом контексте как false, поэтому мы можем ввести немного меньше и сократить ваш пример до:
if ($Table{$key1}{$key2})
{
# do whatever
}
Однако, если значение в этом ключе определено, но является «ложным» (числовая оценка равна ноль или пустая строка), это может привести к ложноотрицательному результату, поэтому мы должны явно проверить определенность, если это возможно:
if (defined $Table{$key1}{$key2})
{
# do whatever
}
Если вы не хотите автоматически оживлять $ Table {$ key1}
, вы можете сначала проверить его существование, , что подводит нас к «лучшему» способу для общего случая :
if (exists $Table{$key1} and defined $Table{$key1}{$key2})
{
# do whatever
}
Если вы собираетесь делать это много для различных полей в хэше , вы можете добавить несколько методов доступа в стиле объектно-ориентированных приложений, которые будут выполнять эту работу за вас:
sub has_field
{
my ($this, $fieldName) = @_;
return exists $this->{data} && defined $this->{data}{$fieldName});
}
Я уверен, что вы уже читали это, но не помешает еще раз прочитать соответствующую документацию:
Учитывая выражение, которое задает элемент хэша или элемент массива,
exists
возвращает истину, если указанный элемент в хэше или arr ay когда-либо инициализировался, даже если соответствующее значение не определено. Если элемент не существует, он не активируется автоматически.
...
Элемент хэша или массива может быть истинным, только если он определен, и определен, если он существует, но обратное не всегда верно.
Отлично! Спасибо всем за ответ.
Поскольку автоживирование - проблема для меня, в настоящее время я использую «неудобный» подход, то есть if (существует $ Table {$ key1} && defined $ Table {$ key1} {$ key2}) {
}
У меня это работает, однако, как вы, ребята, сказали, у меня есть 3-4 уровня вложенного хэша, код немного беспорядочный.
Я проверю Data: Diver. Этот выглядит лучше.
Еще раз спасибо,
Вы можете проверить Data::Diver. Он погружается в структуры данных без автовижирования. Синтаксис будет следующим:
if ( defined Dive(\%Table, $key1, $key2) ) { ... }
или даже:
if ( defined(my $value = Dive(\%Table, $key1, $key2) ) ) {
...do something with $value...
}