2009-05-01 14 views
8

he código Perl similar al siguiente:¿Tiene una clave hash no inicializada un valor predeterminado de cero en Perl?

# -- 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 $res vez establecido antes de la iteración sobre los resultados de la consulta sin embargo, el código se ejecuta muy bien.

Cuando coloco 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 del incremento, obtengo un valor de> = 1 según la cantidad de recursos de IPv6 que tenga la organización.

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

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

Respuesta

26

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

De perldoc perlsyn, bajo '' Declaraciones:

Las únicas cosas que hay que declarar en Perl son los formatos de informes y subrutinas (ya veces ni siquiera subrutinas). Una variable contiene el valor indefinido ("undef") hasta que se le haya asignado un valor definido , que es distinto de "undef". Cuando se utiliza como un número, "undef" se trata como 0; cuando se usa como una cadena, es tratada como la cadena vacía, ""; y cuando se utiliza como una referencia que no está asignada a , se trata como un error .

4

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

El término en el lenguaje de Perl es 'autovivido'.

Lo que es probable que desee hacer es usar el exists keyword:

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

La palabra clave exists prueba para ver si la clave está en el hash, no si el valor es undef. use Test :: More tests => 4; my% h = ('a'); ok (existe $ h {a}); ok (! Defined $ h {a}); ok (! Exists $ h {b}); ok (! Defined $ h {b}); – Axeman

+0

Lo sé. El punto es que él necesita entender la auto-confirmación y la diferencia entre una clave que existe pero que no está definida y una clave indefinida y cómo lidiar con cada una, todo lo cual entenderá si sigue el enlace que proporcioné y lee el documentación sobre la palabra clave exists. –

5

Elaborar en el poste de Telémaco, serán indefinidos los valores sin inicializar. Las partes profundas de la estructura son autovivified. Esta es una característica útil donde las estructuras de datos se crean automáticamente para usted. La autovigilancia es genial cuando la quieres, pero puede ser doloroso cuando quieres prevenirla. Hay muchos tutoriales, artículos y publicaciones en Internet sobre la comprensión de la autovigilancia.

Así da un indefinido $ref y $ref->{ipv6}{pa}{'foo'}++, $ref se le asignará un valor de:

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

A continuación, se incrementará la UNDEF, ya numifies undef a 0, obtenemos 0 ++ que es 1. Para obtener el resultado final de: ref->{ipv6}{pa}{'foo'} == 1.

Si tiene advertencias habilitadas, (lo hace use warnings;, ¿no?) Recibirá una advertencia de "valor no inicializado" cuando opere con estos valores indefinidos. Si es el comportamiento deseado para incrementar el valor no inicializado, a continuación, se puede girar el grupo deseado de las advertencias fuera 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]}++; 
    } 
} 

Usted puede encontrar la jerarquía advertencias en perllexwarn.

+2

Los operadores ++ y - no advierten sobre el uso de valores no inicializados. En su lugar, convierten silenciosamente undef a 0. –

+0

En realidad, recuerdo haber visto el mismo comportamiento que daotoad describe, de obtener advertencias de "valor no inicializado" en la autoincrementación. ¿Alguno de ustedes sabe cuál fue la última versión de Perl donde sucedió esto? –

+1

@j_random - Acabo de probar con Perl 5.8, y Michael Carman está en lo cierto. 'perl -w -e '$ foo {bar} ++'' no advierte los valores no inicializados. Tampoco 'perl -w -e '$ foo {bar} + = 2''. '. =', '- = 'y' - 'están bien también. Sin embargo, los otros X = operadores generan advertencias. – daotoad

2

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

Hay un par de características diferentes de Perl que interactúan en su ejemplo.

Inicialmente $res no está definido (por ejemplo, tiene el valor undef). Cuando utiliza un valor no inicializado como referencia de hash (como en $res->{ipv6}...) Perl lo "autoviva" 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 (silenciosamente) cada vez que usa el valor resultante como referencia.

Eventualmente, se autovitificará en el camino hacia $res->{ipv6}{pa}{$row->[2]}, que no está definido. Recuerde que este es solo un valor escalar como $foo. El comportamiento es el mismo que el de decir

my $foo; 
$foo++; 

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

+0

Muy bien, a lo que me refería en realidad era a un valor no inicializado para una clave paricular. :) Gracias también por la explicación – freakwincy

Cuestiones relacionadas