К чему @ $ ref -> {@ keys} пытается получить доступ? - PullRequest
11 голосов
/ 16 ноября 2011

В комментарии к ответу на вопрос о срезах хеша кто-то хотел узнать, как использовать синтаксис стрелки для доступа к срезу хеша через ссылку на хэш, возможно, подумав, что

@$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)
        }
    }
[...]

Откуда берется неопределенное значение? Для каких значений $ref программа нормально завершает работу?

Ответы [ 2 ]

8 голосов
/ 16 ноября 2011

Это недопустимый (или, по крайней мере, не значащий) синтаксис Perl - я немного удивлен, что он не помечен как синтаксическая ошибка.

Сначала я подумал, что пытался вычислить массив @$foo вскалярный контекст и использовать результат в качестве ссылки на хеш, но это не совсем то, что происходит.Скорее, из отладочного вывода, который вы опубликовали, похоже, что он пытается напрямую использовать структуру внутренней переменной массива (AV) в качестве ссылки на хэш (RV), которая является типом скаляра (SV; см. perlguts для деталей).

Я не смотрел на источник, но похоже, что подпрограмма rv2hv либо замечает, что ей присвоена неправильная структура, и возвращает ноль, либо просто пытается использоватьAV как RV и достигает того же эффекта таким образом.(Извините, если это может показаться немного запутанным, прошло уже несколько лет с тех пор, как я последний раз смотрел внутренности Perl.)

Возможно, вы захотите рассмотреть возможность отправки отчета об ошибке.

Кстати,более простой тестовый пример, демонстрирующий эффект: @foo->{bar}.

5 голосов
/ 16 ноября 2011
@$ref->{@keys}

означает

scalar(@$ref)->{@keys}

, поэтому он должен быть эквивалентен

my $ref2 = @$ref;
$ref2->{@keys}

Это не так, это ошибка. Он все еще присутствует в состоянии, близком к текущему, что станет Perl 5.16.0. (v5.15.4, если быть точным)

Пожалуйста, сообщите с помощью инструмента командной строки perlbug. (Просто введите perlbug и ответьте на несколько простых вопросов.)

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