2011-11-16 10 views
10

En un comentario en un answer to a question about hash slices, alguien quería saber cómo utilizar la sintaxis de flecha para acceder a una rebanada de hash a través de una referencia a un hash, pensando tal vez que

@$ref->{@keys} 

lo haría.

Sí, la sintaxis correcta es @$ref{@keys} o @{$ref}{@keys}, pero eso no es el punto de esta pregunta.

Me trataron de resolver la estructura de datos que la expresión con una flecha requiere:

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

Como está escrito, el código de error con

Not an ARRAY reference at ./prog line 12.

Eso tiene sentido: @$ref quiere una referencia a una matriz, así que intenté envolver las referencias hash dentro de una referencia a una matriz anónima. Esos intentos fracasaron con

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

La salida de rastreo es

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

El vertedero sintaxis de la línea print es

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

Dónde está el valor indefinido viene? ¿Para qué valores de $ref el programa finaliza normalmente?

Respuesta

8

No es válida (o al menos no es significativa) Sintaxis de Perl — Estoy un poco sorprendido de que no esté marcado como un error de sintaxis.

Primero pensé que estaba intentando evaluar la matriz @$foo en contexto escalar y usar el resultado como referencia de hash, pero eso no parece ser lo que está pasando. Por el contrario, desde la salida de depuración que publicó, parece más que intenta usar directamente la estructura de la variable de matriz interna (AV) como referencia de hash (RV), que es un tipo de escalar (SV; consulte perlguts para obtener más información).

No he visto la fuente, pero parece que la rutina rv2hv nota que se le ha dado un tipo incorrecto de estructura y devuelve nulo, o simplemente trata de usar el AV como RV y logra el mismo efecto de esa manera. (Lo siento si eso puede sonar un poco confuso, han pasado algunos años desde la última vez que miré las partes internas de Perl.)

Es posible que desee considerar la posibilidad de enviar un informe de error.

BTW, un caso de prueba más simple que demuestra que el efecto es solo @foo->{bar}.

+0

Es válido (incluso si no es significativo), y por lo tanto no debería ser un error de sintaxis. Sin embargo, debería ser un error estricto. – ikegami

5
@$ref->{@keys} 

significa

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

lo que debe ser equivalente a

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

No es, por lo que es un error. Todavía está presente en el estado casi actual de lo que se convertirá en Perl 5.16.0. (v5.15.4, para ser específicos)

Informe mediante la herramienta de línea de comandos perlbug. (Simplemente ingrese perlbug y responda unas simples preguntas.)