En los ejemplos vistos hasta ahora, cuando invocamos una subrutina y le pasamos parámetros
en realidad le estamos pasando una lista de datos, que se llama
@_
.
Cuando pasamos arreglos o tablas como parámetros en realidad los estamos vertiendo
elemento por elemento en
@_
,
lo cual parece un poco estúpido a veces, con el
trabajo que nos dio previamente llenarlos. De hecho, si queremos pasar
por ejemplo dos arreglos a la vez, será imposible que la subrutina que los reciba
sepa donde termina uno y empieza el otro, porque lo que está recibiendo es
@_
.
Por esta razón, cuando pasamos varios parámetros y uno de ellos es un arreglo, debemos
poner al arreglo en última posición, para poder identificarlos después en la subrutina.
Lo mismo se aplica a los valores que devuelve una subrutina con
return
.
## forma correcta de pasar varios parametros y recibir mas de un resultado my ($result1,@result2) = subrutina($arg1,$arg2,@arg3); sub subrutina { my($sarg1,$sarg2,@sarg3) = @_; my ($sresult1,@sresult2); return ($result1,@result2); } ## en cambio, esto no funciona my (@result2,$result1) = subrutina($arg1,@arg3,$arg3); # $result1 queda sin asignar sub subrutina { my($sarg1,@sarg3,$sarg3) = @_; # $sarg3 queda sin asignar my ($sresult1,@sresult2); return (@result2,$result1); }
La forma más económica de pasar parámetros a subrutinas es pasarlos como referencias (ver sección
2.3). De esta manera no pasamos los datos en sí, si no la dirección que ocupan en
memoria. Así no es necesario copiar todos los datos a
@_
y la subrutina que reciba las
referencias puede acceder a los datos en su organización original, ya sean escalares, arreglos
o tablas asociativas.
Otra aplicación de las referencias parámetro es que permiten modificar de forma permanente, no local, los datos pasados como argumento. Finalmente, el paso por referencias permite pasar como parámetro otras subrutinas, lo cual puede ser útil en ocasiones.
Veamos un ejemplo:
#!/usr/bin/perl -w # Ejemplo escrito por Bruno Contreras use strict; ## variables del programa principal my ($escalar , @arreglo1 , @arreglo2); ## asignacion de valores $escalar = 0; @arreglo1 = (1,2,3); @arreglo2 = (4,5,6); ## llamada a subrutina y conversion de la referencia recibida a un arreglo my @resultado = @{ lee_arreglos( $escalar , \@arreglo1 , \@arreglo2 ) }; print "resultado: $resultado[0] , $resultado[1] , $resultado[2]\n"; ############### subrutinas ################## sub lee_arreglos { my ($sarg1,$rarreglo1,$rarreglo2) = @_; # variables locales my @res = ( $sarg1, $rarreglo1->[0], $rarreglo2->[0] ); return \@res; # devuelve una referencia a un arreglo como resultado }
Otro ejemplo es esta función muy útil para reordenar o barajar vectores in situ :
#!/usr/bin/perl -w use strict; my @vector = (1,2,3,4,5,6); fisher_yates(\@vector); foreach my $valor (@vector){ print "$valor\n" } sub fisher_yates { # http://www.perlmonks.org/?node_id=199901 my ($ref_baraja) = @_; my ($cartai,$cartaj) = (scalar(@$ref_baraja),0); while(--$cartai) { $cartaj = int(rand($cartai+1)); @$ref_baraja[$cartai,$cartaj] = @$ref_baraja[$cartaj,$cartai]; } }
Bruno Contreras-Moreira