2011-11-16 12 views
10

In un commento su un answer to a question about hash slices, qualcuno voleva sapere come utilizzare la sintassi freccia per accedere a una fetta hash attraverso un riferimento ad hash, pensando forse che

@$ref->{@keys} 

farebbe così.

Sì, la sintassi corretta è @$ref{@keys} o @{$ref}{@keys}, ma questo è oltre il punto di questa domanda.

ho cercato di capire la struttura di dati che l'espressione con una freccia richiede:

#! /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"; 

Come scritto, il codice non riesce con

Not an ARRAY reference at ./prog line 12.

che abbia un senso: @$ref vuole un riferimento alla un array, quindi ho provato a racchiudere i riferimenti hash all'interno di un riferimento a un array anonimo. Quei tentativi fallirono con

Can't use an undefined value as a HASH reference at ./prog line 12.

L'uscita traccia è

$ 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.

Il dump sintassi per la linea 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) 
     } 
    } 
[...]

casi in cui è il valore indefinito provenienti da? Per quali valori di $ref il programma termina normalmente?

risposta

8

Non valido (o almeno non significativo) Sintassi Perl — Sono un po 'sorpreso che non sia contrassegnato come errore di sintassi.

Prima ho pensato di provare a valutare l'array @$foo in un contesto scalare e utilizzare il risultato come riferimento hash, ma non sembra proprio quello che sta succedendo. Piuttosto, dal l'output di debug che hai postato, sembra più simile sta cercando di utilizzare direttamente la struttura variabile di matrice interna (AV) come riferimento hash (RV), che è un tipo di scalare (SV; vedi perlguts per i dettagli).

Non ho guardato la fonte, ma sembra che la routine rv2hv noti che è stato assegnato il tipo di struttura errato e restituisce null, o cerca semplicemente di usare l'AV come RV e ottiene lo stesso effetto in questo modo. (Scusa se questo può sembrare un po 'confuso, sono passati alcuni anni dall'ultima volta che ho guardato gli interni di Perl.)

Si potrebbe prendere in considerazione l'invio di una segnalazione di bug.

BTW, un banco di prova più semplice che dimostra l'effetto è solo @foo->{bar}.

+0

È valido (anche se non significativo) e quindi non dovrebbe essere un errore di sintassi. Dovrebbe essere un errore severo, comunque. – ikegami

5
@$ref->{@keys} 

significa

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

quindi dovrebbe essere equivalente a

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

Non è, quindi è un bug. È ancora presente nello stato di quasi corrente di quello che diventerà Perl 5.16.0. (V5.15.4, per essere precisi)

Si prega di segnalare utilizzando lo strumento da riga di comando perlbug. (Basta inserire perlbug e rispondere ad alcune semplici domande.)