2009-06-03 2 views
6

Ho una funzione che sta facendo alcuni calcoli e poi passa alcune proprietà in un'altra subroutine questo modo:Come posso usare gli hash come argomenti per le subroutine in 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";  
}  

mio problema è che il risultato della stampa a (DIETA RISULTATO, DIETA VERDETTO) e (quoziente d'intelligenza, IQ RISULTATO) sono entrambi uguali. Come se la variabile% d e% i venissero popolate con le stesse variabili. Qualche idea del perché questo?

se provo spostando tutte e tre le variabili in questo modo:

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

ottengo il seguente errore:

Odd number of elements in hash assignment 

risposta

24

Quando si passa una matrice (o hash) a una subroutine, la subroutine ottenere un elenco dei valori (o coppie di valori chiave). Ecco perché non puoi passare due array (o due hash), perché la subroutine non saprà dove finisce il primo array e inizia il secondo.

Per risolvere questo problema, si dovrebbe passare a riferimenti invece:

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

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

PS: A parte il problema concettuale, il codice dispone anche di questo:

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

Se% de% Ho entrambi assegnato lo stesso valore, non dovrebbe essere una sorpresa quando sono gli stessi in seguito.

+0

Questo ha funzionato perfettamente. Penso che stia interpretando erroneamente i riferimenti tra i vari tipi. (Scalare, Matrice, Hash) Grazie Manni –

+3

Potrebbe essere utile per gli altri se accettassi la risposta allora. (Non che mi dispiaccia i 25 punti di reputazione in alcun modo.) – innaM

3

Quando si passa in %diet e %iq, entrambi appiattita nella matrice arg, così nel vostro print_result, %d contiene tutti gli elementi %diet e %iq.

da risolvere, utilizzare riferimenti del %diet e %iq:

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

Poi nel print_result:

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

Il tuo esempio cercherà un hash chiamato shift! Aggiungi i paran dopo il turno in modo che l'interprete possa dire che vuoi una chiamata di funzione. – mkb

+1

% i non è vuoto, è una copia di% d perché entrambi sono inizializzati da @_. Guarda la risposta di Manni. –

+2

Questo crea copie poco profonde di entrambi gli hash.Ciò significa che le modifiche al primo livello dell'hash non verranno visualizzate nell'originale, ma le modifiche nel secondo o nei successivi livelli lo faranno. Sembra che gli hash siano semplici hash, quindi per ora dovrebbe andare bene (a patto che non ci si aspetti che le modifiche agli hash si propaghino). Se hai bisogno di copie approfondite, dai un'occhiata alla funzione dclone del modulo 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; 

    ... 

} 

Oppure:

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

Cosa ne pensi di fare la risposta del prototipo non il primo che vedrebbero? :) –

4

Si potrebbe voler controllare il mio libro Intermediate Perl, circa un terzo dei quali riguarda i riferimenti e come lavorare con loro. Ciò include il passaggio di strutture dati complesse in subroutine e altri modi in cui i riferimenti rendono la vita più facile. :)

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

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

    ... 
    }