¿Una clave hash no inicializada tiene un valor predeterminado de cero en Perl?
-
03-07-2019 - |
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!
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.