2009-06-03 10 views
6

Tengo una función que está haciendo algunos cálculos y luego pasa algunas propiedades en otra subrutina de este modo:¿Cómo puedo usar los hashes como argumentos para las subrutinas 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";  
}  

Mi problema es que los resultados impresos en (RESULTADO, la dieta VEREDICTO) y (índice de inteligencia, IQ RESULTADO) son los mismos. Como si la variable% d y% i estuvieran pobladas con las mismas variables. ¿Alguna idea de por qué es esto?

si intento cambiando las tres variables de este modo:

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

me sale el siguiente error:

Odd number of elements in hash assignment 

Respuesta

24

Cuando se pasa una matriz (o hash) a una subrutina, la subrutina obtener una lista de los valores (o pares de valores clave). Es por eso que no puede pasar dos matrices (o dos hashes), porque la subrutina no sabrá dónde termina el primer conjunto y comienza el segundo.

Para evitar este problema, debe pasar en las referencias en su lugar:

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

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

PD: Aparte del problema conceptual, su código también cuenta esto:

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

Si% dy% a los dos se les asigna el mismo valor, no debería ser una sorpresa cuando son los mismos después.

+0

Esto funcionó perfecto. Creo que estaba malinterpretando las referencias entre los diversos tipos. (Escalar, Matriz, Hash) Gracias Manni –

+3

Puede ser útil para otros si aceptó la respuesta. (No es que me importen los 25 puntos de reputación de ninguna manera). – innaM

3

Cuando se pasa en %diet y %iq, los dos obtienen aplanada en la matriz arg, por lo que en su print_result, %d contiene todos los elementos de %diet y %iq.

de resolver, utilizar referencias del %diet y %iq:

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

Luego, en print_result:

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

¡Tu ejemplo buscará un hash llamado shift! Agregue parens después del turno para que el intérprete pueda decirle que desea una llamada de función. – mkb

+1

% i no está vacío, es una copia de% d porque ambos se inicializaron desde @_. Ver la respuesta de Manni. –

+2

Esto crea copias superficiales de ambos hashes.Esto significa que los cambios en el primer nivel del hash no aparecerán en el original, pero los cambios en el segundo o posterior nivel sí lo harán. Parece que los hash son hash simples, por lo que debería estar bien por ahora (siempre que no se espere que se propaguen los hash). Si necesita copias profundas, eche un vistazo a la función dclone del módulo almacenable (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; 

    ... 

} 

O:

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

¿Qué tal si hacemos que la respuesta del prototipo no sea la primera que verían? :) –

4

Es posible que desee consultar mi libro Intermediate Perl, aproximadamente un tercio de los cuales trata sobre referencias y cómo trabajar con ellos. Esto incluye pasar estructuras de datos complejas a subrutinas, así como otras formas en que las referencias hacen su vida más fácil. :)

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

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

    ... 
    } 
Cuestiones relacionadas