Une clé de hachage non initialisée a-t-elle une valeur par défaut de zéro en Perl?

StackOverflow https://stackoverflow.com/questions/811515

  •  03-07-2019
  •  | 
  •  

Question

J'ai un code Perl semblable au suivant:

# -- 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 --

$ res n'a jamais été défini avant d'itérer sur les résultats de la requête, mais le code fonctionne correctement.

Lorsque je mets des instructions d'impression avant chaque valeur, des espaces sont vides dans les deux cas, mais si les instructions d'impression sont postérieures à l'application de l'incrément, je reçois une valeur de > = 1 en fonction du nombre de ressources IPv6 de l'organisation.

Ma question est la suivante: est-ce que je suppose que cela signifie qu'une clé de hachage non initialisée en Perl a automatiquement une valeur de zéro?

Désolé si cela semble être une question d'internaute débutante, mais je ne suis tout simplement pas au courant d'une telle construction c'est-à-dire $ hashref- > {foo} - > {bar} ++ où une valeur n'a pas encore été explicitement assignée à $ hashref- > {foo} - > {bar} . Merci d'avance!

Était-ce utile?

La solution

La valeur n'est pas automatiquement zéro. La valeur est indéfinie initialement. Cependant, si vous le traitez comme un nombre (par exemple, appliquez ++ ), alors Perl le traite comme un zéro. Si vous le traitez comme une chaîne (par exemple, appliquez . ), alors Perl le traite comme une chaîne vide.

De perldoc perlsyn , sous "Déclarations":

  

Les seules choses que vous devez déclarer dans   Perl sont des formats de rapport et   sous-routines (et parfois même pas   sous-routines). Une variable détient le   valeur indéfinie ("undef") jusqu'à ce que   été assigné une valeur définie, qui   est autre que "undef". Quand   utilisé comme un nombre, " undef " est traité   comme 0; lorsqu'il est utilisé comme chaîne, il est   traité comme la chaîne vide, " ;; et   utilisé comme référence qui n’est pas & # 8217; t   étant affecté à, il est traité comme un   erreur.

Autres conseils

Pour élaborer sur le message de Télémaque, les valeurs non initialisées seront indéfinies. Les parties profondes de la structure sont autovivifiées . Il s'agit d'une fonctionnalité pratique dans laquelle les structures de données sont créées automatiquement pour vous. L'autovivification est une bonne chose quand vous le voulez, mais cela peut être pénible quand vous voulez l'empêcher. Il existe de nombreux tutoriels, articles et publications sur le net sur la compréhension de l'autovivification.

Donc, étant donné un $ ref et un $ ref- > {ipv6} {pa} {'foo'}} , $ ref recevra la valeur suivante:

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

Ensuite, l’undef sera incrémenté, puisque undef est numéroté à 0, nous obtenons 0 ++ qui est 1. Pour un résultat final de: ref- > {ipv6} {pa} {'foo'} == 1 .

Si vous avez activé les avertissements (vous utilisez des avertissements; , n'est-ce pas?), vous obtiendrez une "valeur non initialisée". avertissement lorsque vous opérez sur ces valeurs non définies. Si le comportement souhaité consiste à incrémenter la valeur unitaire, vous pouvez alors désactiver le groupe d’avertissements souhaité sur une partie limitée de votre code:

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]}++;
    }
}

Vous pouvez trouver la hiérarchie des avertissements dans perllexwarn .

Il est fondamentalement indéfini, mais traité comme s'il valait zéro lorsque vous l'incrémentez.

Le terme utilisé dans le langage Perl est «autovivifié».

Vous souhaitez probablement utiliser le mot clé existe :

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

Il n’existe pas de clé de hachage non-initialisée . Ce qui peut être non initialisé est la valeur pour une clé particulière. Une valeur de hachage est juste une valeur scalaire; ce n'est pas différent d'une variable comme $ foo .

Dans votre exemple, plusieurs fonctionnalités Perl interagissent.

Initialement, $ res n'est pas défini (c'est-à-dire qu'il a la valeur undef ). Lorsque vous utilisez une valeur non initialisée comme référence de hachage (comme dans $ res- > {ipv6} ... ), Perl " autovivifies " comme un. En d’autres termes, Perl crée un hachage anonyme et remplace la valeur de undef par une référence au nouveau hachage. Ce processus se répète (en silence) chaque fois que vous utilisez la valeur résultante comme référence.

Éventuellement, vous autorisez votre chemin vers $ res- > {ipv6} {pa} {$ row- > [2]} , ce qui n'est pas défini. Rappelez-vous qu'il ne s'agit que d'une valeur scalaire telle que $ foo . Le comportement est le même que de dire

my $foo;
$foo++;

Perl fait des choses spéciales lorsque vous utilisez des valeurs non définies. Si vous les utilisez en tant que nombre, Perl les convertit en 0. Si vous les utilisez en tant que chaîne, Perl les convertit en '' (la chaîne vide). Dans la plupart des cas, vous obtenez un "Utilisation de la valeur non initialisée ...". avertissement si vous avez activé les avertissements (ce que vous devriez faire). L'opérateur à incrémentation automatique ( + + ) est cependant un cas particulier. Pour des raisons pratiques, il convertit en silence la valeur de undef en 0 avant de l'incrémenter.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top