Что такое @$ref → {@keys}, пытающийся получить доступ?
В комментарии к отвечу на вопрос об срезах хеша, кто-то хотел знать, как использовать синтаксис стрелок для доступа к хэш-фрагменту через хеш-ссылку, мышление возможно, что
@$ref->{@keys}
сделает это.
Да, правильный синтаксис - это @$ref{@keys}
или @{$ref}{@keys}
, но это не относится к этому вопросу.
Я попытался выработать структуру данных, для которой требуется выражение со стрелкой:
#! /usr/bin/env perl
use strict;
use warnings;
my $ref = {"a" => 1, "b" => 2, "c" => 3};
my @keys = qw/ a b c /;
#$ref = [ { a => 9, b => 8, c => 7 } ];
#$ref = [ { a => {}, b => {}, c => {} } ];
print @$ref->{@keys}, "\n";
Как написано, код не работает с
Not an ARRAY reference at ./prog line 12.
Это имеет смысл: @$ref
хочет ссылку на массив, поэтому я попробовал обернуть хеш-ссылки внутри ссылки на анонимный массив. Эти попытки не удались с помощью
Can't use an undefined value as a HASH reference at ./prog line 12.
Выход трассировки
$ debugperl -Dt prog
[...]
(prog:12) pushmark
(prog:12) padsv($ref)
(prog:12) rv2av
(prog:12) rv2hv
Can't use an undefined value as a HASH reference at prog line 12.
Синтаксический дамп для строки print
-
$ debugperl -Dx prog
[...]
{
484 TYPE = print ===> 2
FLAGS = (VOID,KIDS)
{
485 TYPE = pushmark ===> 486
FLAGS = (SCALAR)
}
{
372 TYPE = helem ===> 371
FLAGS = (SCALAR,KIDS)
{
487 TYPE = rv2hv ===> 361
TARG = 5
FLAGS = (SCALAR,KIDS,REF)
PRIVATE = (STRICT_REFS)
{
373 TYPE = rv2av ===> 487
TARG = 4
FLAGS = (SCALAR,KIDS,REF)
PRIVATE = (STRICT_REFS)
{
486 TYPE = padsv ===> 373
TARG = 1
FLAGS = (SCALAR,MOD)
}
}
}
{
361 TYPE = padav ===> 372
TARG = 2
FLAGS = (SCALAR)
}
}
{
371 TYPE = const ===> 484
TARG = 19
FLAGS = (SCALAR)
}
}
[...]
Где находится значение undefined? Для каких значений $ref
программа заканчивается нормально?
Ответы
Ответ 1
Недействительно (или, по крайней мере, не имеет смысла) Синтаксис Perl — Я немного удивлен, что это не помечено как синтаксическая ошибка.
Сначала я подумал, что он пытается оценить массив @$foo
в скалярном контексте и использовать результат как хеш-ссылку, но это не совсем похоже на то, что происходит.
Скорее, из выведенного отладочного вывода он больше похож на попытку напрямую использовать структуру внутренних массивов (AV) как хеш-ссылку (RV), которая является типом скаляра (SV; см. perlguts).
Я не смотрел на источник, но похоже, что подпрограмма rv2hv
либо замечает, что ему задан неправильный тип структуры и возвращает значение null, либо просто пытается использовать AV как RV и достигает такой же эффект таким образом. (Извините, если это может показаться немного запутанным, прошло несколько лет с тех пор, как я в последний раз смотрел на внутренности perl.)
Возможно, вы захотите рассмотреть вопрос об отправке отчета об ошибке.
BTW, более простой тестовый пример, демонстрирующий эффект, всего лишь @foo->{bar}
.
Ответ 2
@$ref->{@keys}
означает
scalar(@$ref)->{@keys}
поэтому он должен быть эквивалентен
my $ref2 = @$ref;
$ref2->{@keys}
Это не так, поэтому это ошибка. Он все еще присутствует в почти текущем состоянии того, что станет Perl 5.16.0. (v5.15.4, чтобы быть конкретным)
Пожалуйста, сообщите, используя инструмент командной строки perlbug
. (Просто введите perlbug
и ответьте на несколько простых вопросов.)