2011-02-03 10 views
16

Necesita ayuda para descubrir cómo hacerlo. Mi código:¿Cómo paso un hash a la subrutina?

my %hash; 
$hash{'1'}= {'Make' => 'Toyota','Color' => 'Red',}; 
$hash{'2'}= {'Make' => 'Ford','Color' => 'Blue',}; 
$hash{'3'}= {'Make' => 'Honda','Color' => 'Yellow',}; 


&printInfo(%hash); 

sub printInfo{ 
    my (%hash) = %_; 
    foreach my $key (keys %_{  
    my $a = $_{$key}{'Make'}; 
    my $b = $_{$key}{'Color'}; 
    print "$a $b\n"; 
    } 
} 

Respuesta

27

La manera fácil, que puede provocar problemas cuando el código evoluciona, es simplemente asignando la matriz predeterminada @_ (que contiene todos los pares clave-valor como una lista par) al% hash que luego se reconstruye de acuerdo. Así que el código se vería así:

sub printInfo { 
    my %hash = @_; 
    ... 
} 

La mejor manera sería pasar el hash como referencia a la subrutina. De esta forma, aún podría pasar más parámetros a su subrutina.

printInfo(\%hash); 
sub PrintInfo { 
    my %hash = %{$_[0]}; 
    ... 
} 

Una introducción al uso de referencias en Perl se puede encontrar en el perlreftut

+1

+1: para 'mi% hash =% {$ _ [0]};' –

8

Estás muy, muy cerca. No hay %_ para pasar hashes, se debe pasar en @_. Por suerte, se asignan valores hash usando un contexto de la lista, por lo

sub printInfo { 
    my %hash = @_; 
    ... 
} 

harán que funcione!

También tenga en cuenta que el uso de & en frente de la llamada de subrutina ha sido, en la mayoría de los casos, innecesario desde al menos Perl 5.000. Puede llamar a las subrutinas de Perl como en otros idiomas en estos días, con solo el nombre y los argumentos. (Como @mob señala en los comentarios, hay algunos casos en los que así lo requiere; ver perlsub entender esto más, si está interesado.)

+0

'&' suele ser opcional, y (a menudo) no es una buena práctica usarlo debido a la forma en que Perl genera los argumentos predeterminados, pero no está en desuso. A veces es necesario y, a veces no es necesario, pero aún puede hacer que el código sea más legible. – mob

+0

Usted, señor, es técnicamente correcto: el mejor tipo de corrección. Aclaré mi comentario sobre eso. –

+1

No * "y quizás más viejo" *. El 'y' todavía era ** generalmente ** necesario en llamadas de función en la última versión 4.036 de Perl4 de 1993-Feb-05. Confía en mí, estuve allí. ☺ La única forma de evitarlo era usar la sintaxis 'do mysubname()', que aún funciona bien, por cierto, para mucha sorpresa de los pocos que se tropiezan con ella. O sobre eso – tchrist

6

Creo que desee

my %hash; 
$hash{'1'}= {'Make' => 'Toyota','Color' => 'Red',}; 
$hash{'2'}= {'Make' => 'Ford','Color' => 'Blue',}; 
$hash{'3'}= {'Make' => 'Honda','Color' => 'Yellow',}; 

printInfo(%hash); 

sub printInfo{ 
    my %hash = @_; 
    foreach my $key (keys %hash){  
    my $a = $hash{$key}{'Make'}; 
    my $b = $hash{$key}{'Color'}; 
    print "$a $b\n"; 
    } 
} 

En la línea printInfo(%hash) el %hash se amplía a una lista con los pares clave-valor alternativos.

En printInfo, el @_ es esta lista que, y asignada a %hash, crea nuevamente las claves con su valor correspondiente de los elementos alternantes en la lista.

3

Puede pasar como

  1. La lista de argumentos do_hash_thing(%hash)
  2. Una referencia al hash en el argumento list `do_hash_thing (@args_before, \% hash, @args_after)
  3. Como referencia por prototipo, que funciona como keys y otros operadores hash.

La lista funciona de esta manera:

sub do_hash_thing { 
    my %hash = @_; 
    ... 
} 

do_hash_thing(%hash); 

Esto también le permite "corriente" argumentos de hash, así:

do_hash_thing(%hash_1, %hash_2, parameter => 'green', other => 'pair'); 

Por obras de referencia como esto:

sub do_hash_thing { 
    my $hash_ref = shift; 
    ... 
} 

do_hash_thing(\%hash, @other_args); 

Aquí por el prototipo (\%@). El prototipo hace que Perl busque un hash en el primer argumento y lo pase por referencia.

sub do_hash_thing (\%@) { 
    my $hash_ref = shift; 
    ... 
} 

do_hash_thing(%hash => qw(other args)); 
# OR 
do_hash_thing %hash => qw(other args); 

Advertencia: los prototipos no funcionan en los métodos.

+0

'(%)' es incluso una lista de longitud, '(\%)' es hash ref –

4

La mejor manera de pasar hashes y matrices es por reference. Una referencia es simplemente una forma de hablar sobre una estructura de datos compleja como un único punto de datos, algo que se puede almacenar en una variable escalar (como $foo).

Lea en references, por lo que entiende cómo crear una referencia desreferencia una referencia para recuperar sus datos originales.

Lo básico: usted antepone su estructura de datos con una barra diagonal inversa para obtener la referencia a esa estructura.

my $hash_ref = \%hash; 
my $array_ref = \@array; 
my $scalar_ref = \$scalar; #Legal, but doesn't do much for you... 

Una referencia es una ubicación de memoria de la estructura original (además de una pista acerca de la estructura):

print "$hash_ref\n"; 

imprimirá algo como:

HASH(0x7f9b0a843708) 

Para obtener la referencia de vuelta en un formato utilizable, simplemente ponga la referencia en el sigil correcto al frente:

my %new_hash = %{ $hash_ref }; 

Debe aprender a usar referencias ya que esta es la forma en que puede crear estructuras de datos extremadamente complejas en Perl, y cómo funciona Perl orientado a objetos.


Digamos que quiere pasar tres hashes a su subrutina.Estos son los tres valores hash:

my %hash1 = (this => 1, that => 2, the => 3, other => 4); 
my %hash2 = (tom => 10, dick => 20, harry => 30); 
my %hash3 = (no => 100, man => 200, is => 300, an => 400, island => 500); 

voy a crear las referencias para ellos

my $hash_ref1 = \%hash1; 
my $hash_ref2 = \%hash2; 
my $hash_ref3 = \%hash3; 

Y ahora sólo tiene que pasar las referencias:

mysub ($hash_ref1, $hash_ref2, $hash_ref3); 

Las referencias son escalares de datos, así que no hay problema para pasarlos a mi subrutina:

sub mysub { 
    my $sub_hash_ref1 = shift; 
    my $sub_hash_ref2 = shift; 
    my $sub_hash_ref3 = shift; 

Ahora, simplemente me desreferencia, y mi subrutina puede usarlos.

my %sub_hash1 = %{ $sub_hash_ref1 }; 
    my %sub_hash2 = %{ $sub_hash_ref2 }; 
    my %sub_hash3 = %{ $sub_hash_ref3 }; 

Se puede ver lo que una referencia es una referencia a utilizando el comando ref:

my $ref_type = ref $sub_hash_ref; # $ref_type is now equal to "HASH" 

Esto es útil si desea asegurarse de que está siendo pasado el tipo correcto de la estructura de datos .

sub mysub { 
    my $hash_ref = shift; 

    if (ref $hash_ref ne "HASH") { 
     croak qq(You need to pass in a hash reference); 
    } 

También tenga en cuenta que estas son las referencias a memoria, por lo que la modificación de la referencia modificará el hash original:

my %hash = (this => 1, is => 2, a => 3 test => 4); 
print "$hash{test}\n"; # Printing "4" as expected 
sub mysub (\%hash); # Passing the reference 
print "$hash{test}\n"; # This is printing "foo". See subroutine: 


sub mysub { 
    my $hash_ref = shift; 

    $hash_ref->{test} = "foo"; This is modifying the original hash! 
} 

Esto puede ser bueno - que le permite modificar los datos pasados ​​a la subrutina, o malo - le permite involuntariamente modificar los datos pasados ​​a la subrutina original.

Cuestiones relacionadas