perl autovivification

¿Cómo desactivo la autovibición en Perl?



autovivification (5)

Puede bloquear el hash usando una de las funciones de Hash :: Util (un módulo principal).

use Hash::Util qw( lock_keys unlock_keys ); my $some_ref = { akey => { deeper => 1 } }; lock_keys %$some_ref; print "too deep" if $some_ref->{deep}{shit} == 1;

Ahora la última declaración lanzará una excepción:

Attempt to access disallowed key ''deep'' in a restricted hash

La desventaja es, por supuesto, que tendrá que tener mucho cuidado al buscar claves en el hash para evitar excepciones, es decir, use un lof de " if exists ... " para verificar las claves antes de acceder a ellas.

Si necesita agregar claves al hash nuevamente más adelante, puede desbloquearlo:

unlock_keys %$some_ref; $some_ref->{foo} = ''bar''; # no exception

Supongamos que tiene una aplicación ENORME "desarrollada";) por un gran equipo. Aquí hay un modelo simplificado del desastre potencial que puede ocurrir cuando alguien comprueba demasiado profundamente en una estructura de datos. Si no es posible deshabilitar la autovificación por completo o en el alcance, ¿cómo evitar esto? Muchas gracias :) !!!!

use strict; use warnings;use Data::Dumper; my $some_ref = {akey=>{deeper=>1}}; print Dumper($some_ref ); if($some_ref->{deep}{doot} == 1){ print ''too deep ''.$/; } if($some_ref->{deep}){ print ''Already in a deep doot''.$/; } print Dumper($some_ref );

Esto produce lo siguiente:

$VAR1 = { ''akey'' => { ''deeper'' => 1 } }; Use of uninitialized value in numeric eq (==) at autovivify_test.pl line 5. Already in a deep doot $VAR1 = { ''deep'' => {}, ''akey'' => { ''deeper'' => 1 } };

Sí, sé que hay una advertencia, pero ... puede ser demasiado tarde.

Hola chicos, puede ser útil decir que mi hashref hace referencia a un HASH atado.

¿Puede ser que si implemento un buen método FETCH que verifique los controles más profundos en la estructura, resolveré fácilmente mi problema?

Miré Tie :: StrictHash , Tie :: Hash y Perltie . Aquí está la versión simplificada de mi solución:

#!/usr/bin/env perl; #test_tie.pl package StrictHash; use strict; use warnings; use Tie::Hash; our @ISA = qw(Tie::StdHash); use Carp; sub TIEHASH { my $class = shift; my $hash = bless {@_}, $class; return $hash; } ##======================================================================== ## FETCH fails if applied to a member that doesn''t exist. ##======================================================================== sub FETCH { my ($hash, $key) = @_; Carp::confess "key ''$key'' does not exist" unless exists $hash->{$key}; return $hash->{$key}; } ##======================================================================== package main; use strict;use warnings;use Data::Dumper; #Imagine StrictHash is in ./StrictHash.pm #use StrictHash; my %hash; tie %hash, ''StrictHash'', akey => {deeper=>1} ; my $some_ref =/%hash; print Dumper($some_ref ); if($some_ref->{deep}{doot} == 1){ print ''too deep ''.$/; }

Lo que logré es tocar solo un lugar en la aplicación. Ahora todos los lugares como if ($ some_ref -> {deep} {doot}) causarán la muerte con stack-trace. Entonces los encontraré y corregiré fácilmente. Y nuevas escrituras de este tipo NO serán posibles. Perl también es bueno para grandes aplicaciones, solo necesitas saber más;).

¡Gracias a todos! Espero que esto ayude a otros también.


Otra opción es usar Data :: Diver para acceder a sus estructuras de datos.

if( 1 == Dive($some_ref, qw/ deep structures are not autovivified now / ) { Do_Stuff(); }


Relativamente nuevo es el módulo de autovivification , que le permite hacer esto:

no autovivification;

Muy claro.


Es posible que desee utilizar un objeto en lugar del hash (consulte Moose ) o use un hash vinculado estricto . O puede convertir advertencias en errores, si realmente desea:

use warnings NONFATAL => ''all'', FATAL => ''uninitialized'';


Subí a @zoul , pero debes dar un paso más.

Escribir pruebas

Debe tener su código cubierto con pruebas, y debe ejecutar algunas de esas pruebas con

use warnings FATAL => ''uninitialized'';

declarado en el caso de prueba en sí. Es la única forma de abordar la preocupación que tienes con los desarrolladores que no verifican las cosas con anticipación. Asegúrate de que su código esté probado.

Y dé un paso más allá y haga que sea más fácil ejecutar sus pruebas en Devel :: Cover para obtener un informe de cobertura.

cover -delete PERL5OPT=''-MDevel::Cover'' prove -l cover -report Html_basic

Y luego verifique las líneas de código y las declaraciones se ejecutan mediante las pruebas, de lo contrario, hacer que esas advertencias sean fatales hará que el código muera en un momento inesperado más tarde.