Pregunta

Tengo un código Perl similar al siguiente:

# -- start --

my $res;

# run query to fetch IPv6 resources
while( my $row = $org_ip6_res->fetchrow_arrayref )
{
    if( $row->[4] =~ /PA/ ) {
        $res->{ipv6}{pa}{$row->[2]}++;
    } elsif( $row->[4] eq 'PI' ) {
        $res->{ipv6}{pi}{$row->[2]}++;
    }
}

# -- stop --

En ningún momento se ha establecido $ res antes de iterar sobre los resultados de la consulta, pero el código funciona bien.

Cuando pongo declaraciones de impresión antes de cada valor obtengo espacios en blanco en ambos casos, pero si las declaraciones de impresión aparecen después de que se haya aplicado el incremento, obtengo un valor de > = 1 dependiendo de cuántos recursos IPv6 tenga la organización.

Mi pregunta es, ¿tomo esto como una clave hash no inicializada en Perl que automáticamente tiene un valor de cero?

Lo siento si aparece como una pregunta de novato, pero simplemente no estoy familiarizado con tal construcción es decir, $ hashref- > {foo} - > {bar} ++ donde aún no se ha asignado explícitamente un valor a $ hashref- > {foo} - > {bar} . Gracias de antemano!

¿Fue útil?

Solución

El valor no es automáticamente cero. El valor es indefinido inicialmente. Sin embargo, si lo trata como un número (por ejemplo, aplíquele ++ ), entonces Perl lo trata como cero. Si lo trata como una cadena (por ejemplo, aplique . ), entonces Perl lo trata como una cadena vacía.

Desde perldoc perlsyn , bajo 'Declaraciones':

  

Las únicas cosas que necesitas declarar en   Perl son formatos de informe y   subrutinas (ya veces ni siquiera   subrutinas). Una variable sostiene la   valor indefinido (" undef ") hasta que tenga   ha asignado un valor definido, que   es cualquier otra cosa que " undef " ;. Cuando   utilizado como un número, " undef " es tratado   como 0; cuando se utiliza como una cadena, es   tratada como la cadena vacía, " " ;; y   cuando se usa como una referencia que no es   siendo asignado a, es tratado como un   error.

Otros consejos

Para profundizar en la publicación de Telémaco, los valores no inicializados no estarán definidos. Las partes profundas de la estructura son autovivified . Esta es una característica útil donde las estructuras de datos se crean automáticamente. La autovivificación es excelente cuando la quieres, pero puede ser un dolor cuando quieres prevenirla. Hay muchos tutoriales, artículos y publicaciones en la red sobre la comprensión de la autovivificación.

Por lo tanto, dado un $ ref y $ ref- > {ipv6} {pa} {'foo'} ++ no definidos, $ ref se le asignará un valor de:

$ref = { 
     ipv6 => { 
          pa => { 
              foo => undef
          }
     }
};

Entonces la undef se incrementará, ya que undef numera a 0, obtenemos 0 ++ que es 1. Para obtener un resultado final de: ref- > {ipv6} {pa} {'foo'} == 1 .

Si tiene habilitadas las advertencias ( usa advertencias; , ¿no es así?) obtendrá un " valor no inicializado " advertencia cuando opera con estos valores indefinidos. Si es el comportamiento deseado aumentar el valor unitario, entonces puede desactivar el grupo de advertencias deseado sobre una parte limitada de su código:

use strict;
use warnings;
my $res;

// run query to fetch IPv6 resources
while( my $row = $org_ip6_res->fetchrow_arrayref )
{   no warnings 'uninitialized';
    if( $row->[4] =~ /PA/ ) {
        $res->{ipv6}{pa}{$row->[2]}++;
    } elsif( $row->[4] eq 'PI' ) {
        $res->{ipv6}{pi}{$row->[2]}++;
    }
}

Puede encontrar la jerarquía de advertencias en perllexwarn .

Básicamente no está definido, pero se trata como si fuera cero cuando lo incrementas.

El término en el lenguaje Perl es 'autovivified'.

Lo que probablemente quiera hacer es usar la palabra clave existente :

$res->{ipv6}{pa}{$row->[2]}++ if exists($res->{ipv6}{pa}{$row->[2]});

No existe una clave hash no inicializada. Lo que no se puede inicializar es el valor para una clave en particular. Un valor hash es solo un valor escalar; no es diferente de una variable como $ foo .

Hay un par de funciones Perl diferentes que interactúan en tu ejemplo.

Inicialmente $ res no está definido (es decir, tiene el valor undef ). Cuando utiliza un valor no inicializado como referencia de hash (como en $ res- > {ipv6} ... ) Perl " autovivifies " como uno Es decir, Perl crea un hash anónimo y reemplaza el valor de undef con una referencia al nuevo hash. Este proceso se repite (en silencio) cada vez que utiliza el valor resultante como referencia.

Finalmente, autovivificarás tu camino a $ res- > {ipv6} {pa} {$ row- > [2]} , que no está definido. Recuerde que esto es solo un valor escalar como $ foo . El comportamiento es el mismo que decir

my $foo;
$foo++;

Perl hace cosas especiales cuando usas valores indefinidos. Si los usa como un número, Perl los convierte a 0. Si los usa como una cadena, Perl los convierte a '' (la cadena vacía). En la mayoría de las circunstancias, obtendrá un "Uso de valor no inicializado ..." advertencia si tiene habilitadas las advertencias (que debería). El operador auto-incremento ( + + ) es un caso especial, sin embargo. Para mayor comodidad, convierte el valor de undef a 0 en silencio antes de incrementarlo.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top