Что такое @$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 и ответьте на несколько простых вопросов.)