viernes, 19 de marzo de 2010

SUBRUTINAS

Se pueden colocar en cualquier sitio en el programa, pero se suelen definir todas juntas o bien al principio o bien al final del programa.
Otro aspecto de interés en PERL es la definición y manejo de subrutinas.

A modo de ejemplo, una subrutina tiene el aspecto:

sub una_subrutina {
print "\n Mi primera subrutina en Perl...\n";
}

Comienzan por la palabra reservada sub, a continuación ponemos el nombre de la subrutina y el bloque o cuerpo.

Para llamarla desde el programa principal, debemos anteponer al nombre de la subrutina el símbolo &:

# llamada sin parametros
&una_subrutina;

# llamada con un parametro
&una_subrutina("hola");

# llamada con dos parametros
&una_subrutina(5-3, "segundo parametro");

Si llamamos a una subrutina con más parametros de los que debe recibir, no se produce ningún error, simplemente se ignoran los sobrantes.

Hacer un programa que incluye la subrutina vista más arriba. Cada vez que se llame a la subrutina debe mostrar el mismo mensaje (hasta que aprendamos a pasarle parámetros).



--------------------------------------------------------------------------------


2. Parametros.
Cuando una subrutina recibe parametros, estos son pasados como una lista en la variable-array especial @_. Ese array no tiene nada que ver con $_.
Si recordarmos las matrices veremos que cada uno de los parámetros será una variable dentro de la matriz que se direcciona así $_[0], $_[1],etc...


Llamada a la subrutina con 2 parámetros:
&saludo ("Hola","Mundo\n");

@_=("Hola","Mundo\n")

equivaldría a:

$_[0]="Hola" y $_[1]="Mundo\n"

El siguiente programa simplemente imprime la lista de argumentos con que se ha llamado:

sub print_args {
print "\n@_\n";
}

# imprimira "llamada con dos parametros"
&print_args("llamada con", "dos parametros");


# imprimira "llamada con TRES parametros"
&print_args("llamada con", "TRES", "parametros");

Al igual que otra variable-array, puede ser accedida con la notación de corchetes, mediante las variables $_[0], $_[1], ..., que nada tienen que ver con la variable $_:

sub print_2_args {
print "Primero= $_[0] \n";
print "Segundo= $_[1] \n";
}

Hacer un programa con una subrutina que recibe dos parámetros y los muestra por pantalla.


Otras variables que no sean las @_, $_[i] o las definidas como locales a que hagamos referencia dentro del la subrutina serán globales, con lo cual si modificamos alguna de ellas, al salir de la subrutina, se habrán modificado:

sub vars_globales {
$a =~ tr/a-z/A-Z/;
$b =~ tr/a-z/A-Z/;
( $a =~ /$b/ || $b =~ /$a/ );
}

primero se pasan los parametros a mayúsculas y después se comprueba si una contiene a la otra. Pero al volver de la llamada a la función, las variables que se le pasaron se ven modificadas:
$a = "liMonaDa";
$b = "lImOn";
$r = &vars_globales;
print "\n$r $a $b\n";

Imprimiría:
1 LIMONADA LIMON

A veces esto nos interesará, pero a veces no. Cuando no queramos ver modificadas las variables globales desde dentro de una subrutina, deberemos utilizar variables locales.
Si asignamos un valor a una nueva variable dentro de una subrutina, y esa variable no es local a la subrutina, se creará como global, pudiendo utilizarse al volver de la llamada a la subrutina:

sub vars_globales2 {
$nueva_variable = "valor";
}

&vars_globales2;
print "$nueva_variable"; # imprime "valor"


--------------------------------------------------------------------------------


3. Variables locales.
La variable @_, al igual que $_[0], $_[1], ... son locales a la subrutina. Perl permite que podamos definir en las subrutinas nuestras variables locales, mediante la palabra reservada local:
sub vars_locales {
local($a, $b);
($a, $b) = ($_[0], $_[1]);
( $a =~ /$b/ || $b =~ /$a/ );
}

devuelve verdadero si el primer parametro o el segundo esta dentro del otro (o falso en caso contrario).
Esta es la forma de evitar el problema que tenía la subrutina vars_globales
Las variables locales son útiles para no modificar las variables globales.

Al definir las variables locales podemos asignarles el valor en la misma línea con:

local($a, $b) = ($_[0], $_[1]);


--------------------------------------------------------------------------------


4. Valores de retorno.
PERL también nos permite retornar valores y lo hace tomando como retorno el último valor escalar que se emplee en la subrutina. El resultado que devuelve una subrutina es la última cosa evaluada.
Así, la subrutina que vimos antes que imprimía los parametros que recibía, devuelve siempre un 1 (verdadero), que es lo que devuelve la orden print.

Para devolver un valor, podemos hacer dos cosas:

sub maximo {
if( $_[0] > $_[1] ) {
$_[0];
}else{
$_[1];
}
}

$mayor = &maximo(37,23); #devuelve 37

o bien:
sub maximo {
if( $_[0] > $_[1] ) {
return $_[0];
}else{
return $_[1];
}
}

$mayor = &maximo(37,23); #devuelve 37

Hacer un programa que incluye una subrutina que devuelve un valor (se puede usar la subrutina anterior) y que el programa llamador la muestre.


Si no utilizamos "return", se devuelve el valor de lo último que evaluáramos:
sub Suma {
$Total = $_[0] + $_[1];
}

# Llamada a la subrutina
print &Suma (2,3);

La suma, el valor devuelto por la subrutina, y la salida del programa será: 5

Si tras la variable $Total tuviesemos otra variable, el valor final retornado sería el valor de esta última variable:
sub Suma {
$Total=$_[0] + $_[1];
$saludo = "Hola Mundo\n";
}

# Llamada a la subrutina
print &Suma (2,3);

La suma dará 5, pero el valor devuelto por la subrutina y la salida del programa será: Hola Mundo


--------------------------------------------------------------------------------

5. Paso de valores por referencia
Hasta ahora hemos visto el pasa de parámetros por valor, es decir, no es posible cambiar los valores globales de los argumentos. Para hacer esto posible es necesario pasar a la función no los valores, sino los nombres de estas variables. Este modo se denomina paso por referencia y se implementa prefijando el nombre de la variable con un arterisco *.
En el momento de la definición de una funcioón cuyos argumentos se pasan por referencia, la asignación de los argumentos a las variables locales se hacen mediante el operador local(*nombre). El ejemplo siguiente ilustra este modo de paso de argumentos describiendo la rutina swap que hace la permuta de los valores de los argumentos.

sub swap {
local(*x, *y) = @_; # asignación local de los argumentos
local($t); # variable local
$t = $x;
$x = $y;
$y = $t;
return @_; # resultado de la función
}
$a = 4; $b = 1;
&swap(*a, *b); # $a =1; $b = 4;
Resulta esencial que la asignación de los argumentos a las variables locales se haga mediante el operador local. Ya que la asignación directa de la variable mediante *nombre=valor modifica las ocurrencias de la variable nombre (globalmente en el script, sino se ha declarado explícitamente como local). Por ejemplo:

sub swap {
(*a, *b) = @_; # asignación de argumentos
local($t);
$t = $a;
$a = $b;
$b = $t;
return @_;
}
$a = 4; $b = 1;
$x = "pi"; $y = 1.414;
&swap(*x, *y); # $x = 1.414; $y = "pi"
print "a=$a, b=$b\n"; # $a = 1.414; $b = "pi"

No hay comentarios:

Publicar un comentario