2009-06-03 8 views
6

J'ai une fonction qui fait des calculs et passe ensuite quelques propriétés dans une autre sous-routine comme ceci:Comment puis-je utiliser des hachages comme arguments pour des sous-routines en Perl?

sub get_result { 
    my $id = 1;  
    my %diet = (result => 28, 
       verdict => 'EAT MORE FRUIT DUDE...'  
       ); 

    my %iq = (result => 193, 
       verdict => 'Professor Einstien' 
      );   
    print_result($id, %diet, %iq); 
} 

sub print_result {  
    my $id = shift;  
    my %d = @_;  
    my %i = @_;  

    print "IQ: $id\n";  
    print "DIET RESULT: $d{result}\n";  
    print "DIET VERDICT: $d{verdict}\n";  
    print "IQ RESULT: $i{result}\n";  
    print "IQ VERDICT: $i{verdict}\n";  
}  

Mon problème est que les résultats imprimés en (résultat DIET, DIET VERDICT) et (IQ POINTAGE, IQ RÉSULTAT) sont les mêmes. Comme si les variables% d et% i étaient peuplées avec les mêmes variables. Des idées pourquoi c'est?

Si je tente de déplacer les trois variables comme ceci:

my $id = shift;  
my %d = shift;  
my %i = shift; 

Je reçois l'erreur suivante:

Odd number of elements in hash assignment 

Répondre

24

Lorsque vous passez un tableau (ou hachage) à un sous-programme, la sous-routine obtenir une liste des valeurs (ou paires de valeurs clés). C'est pourquoi vous ne pouvez pas passer deux tableaux (ou deux hachages), car le sous-programme ne saura pas où le premier tableau se termine et le second commence.

Pour contourner ce problème, vous devez passer des références à la place:

my %hash1 = (foo => 'bar'); 
my %hash2 = (bar => 'baz'); 
subroutine(\%hash1, \%hash2); 

sub subroutine { 
    my ($hashref1, $hashref2) = @_; 
    print $hasref1->{foo}, $hashref2->{bar}; 
} 

PS: En dehors du problème conceptuel, votre code comporte également ceci:

my %d = @_;  
my %i = @_;  

Si% d et% On m'a attribué la même valeur à tous les deux, cela ne devrait pas surprendre quand ils sont identiques par la suite.

+0

Cela a fonctionné parfaitement. Je pense que j'ai mal interprété les références entre les différents types. (Scalaire, Array, Hash) Merci Manni –

+3

Il pourrait être utile pour les autres si vous avez accepté la réponse alors. (Ce n'est pas que les 25 points de réputation me dérangeraient de quelque façon que ce soit.) – innaM

3

Lorsque vous passez %diet et %iq, ils ont tous deux s'aplatissent dans le tableau de arg, donc dans votre print_result, %d contient tous les éléments %diet et %iq.

Résoudre des problèmes, utilisez références du %diet et %iq:

print_result($id, \%diet, \%iq); 

Puis, en print_result:

my $id = shift; 
my %d = %{+shift}; 
my %i = %{+shift}; 
+2

Votre exemple cherchera un hash nommé shift! Ajoutez des parens après le changement pour que l'interprète puisse vous dire vouloir un appel de fonction. – mkb

+1

% i n'est pas vide, c'est une copie de% d car les deux sont initialisés à partir de @_. Voir la réponse de Manni. –

+2

Cela crée des copies superficielles des deux hachages.Cela signifie que les modifications apportées au premier niveau du hachage n'apparaîtront pas dans l'original, mais que les modifications du second niveau ou des niveaux ultérieurs le seront. Il semble que les hachages soient des hachages simples, donc cela devrait être bon pour le moment (tant que les modifications des hachages ne devraient pas se propager). Si vous avez besoin de copies profondes, jetez un oeil à la fonction dclone du module Storable (http://perldoc.perl.org/Storable.html). –

0
use strict; 
use warnings; 

sub get_result { 

    ... 

    print_result($id, \%diet, \%iq); 
    # or 
    print_result($id, {%diet}, {%iq}); 
} 


sub print_result{ 
    my($id, $diet_h, $iq_h) = @_; 
    my %diet = %$diet_h; 
    my %iq = %$iq_h; 

    ... 

} 

Ou:

use strict; 
use warnings; 

sub print_result($\%\%); 

sub get_result{ 

    ... 

    print_result($id, %diet, %iq); 
} 

sub print_result($\%\%){ 
    my($id, $diet_h, $iq_h) = @_; 
    my %diet = %$diet_h; 
    my %iq = %$iq_h; 

    ... 

} 
+2

Que diriez-vous de faire la réponse du prototype pas le premier qu'ils verraient? :) –

4

Vous voudrez peut-être consulter mon livre Intermediate Perl, dont environ un tiers traite de références et comment travailler avec elles. Cela inclut le passage de structures de données complexes dans des sous-routines ainsi que d'autres façons dont les références vous facilitent la vie. :)

some_sub(\%hash); 
some_sub({ key => 'value' }); 
some_sub($hash_ref); 

sub some_sub { 
    my($hash_ref) = @_; 

    ... 
    } 
Questions connexes