Usando Subrutinas

Anuncio
CONTENIDO
Usando Subrutinas ......................................................................................................... 1
Qué es una Subrutina ................................................................................................. 1
Definiendo e invocando una subrutina........................................................................ 1
Forward References a Subrutinas ....................................................................... 4
Retornando un valor desde una Subrutina ................................................................. 4
Valores de Retorno y Expresiones Condicionales............................................... 6
La Sentencia return..................................................................................................... 8
Usando variables locales en Subrutinas ..................................................................... 9
Inicialización de variables locales ...................................................................... 11
Pasando valores a una Subrutina ............................................................................. 11
Pasando una lista a una Subrutina .................................................................... 13
Llamando Subrutinas desde otras Subrutinas .......................................................... 14
Subrutinas Predefinidas ............................................................................................ 16
Ejemplo de BEGIN .................................................................................... 16
Ejemplo de END ......................................................................................... 16
AUTOLOAD ......................................................................................................... 17
QUE ESTA MAL?...................................................................................................... 18
Usando Subrutinas
Qué es una Subrutina
En Perl, 1 subrutina es una porción de código separada usada para efectuar una tarea
particular. El programa PERL ejecuta esa porción de código llamando o invocando la
subrutina.
Una Subrutina se usa para alguno de estos dos propósitos:
•
Para partir un programa en partes pequeñas haciéndolo mas fácil de leer y mas
entendible.
•
Para permitirnos usar una porción de código para llevar a cabo la misma tarea
varias veces eliminando la duplicación.
Definiendo e invocando una subrutina.
Listado 9.1 muestra como una subrutina trabaja. Este programa llama una subrutina que
lee una línea con números desde el standard input file y los separa. El programa luego
efectúa su suma.
Listado 9.1. Un programa que usa una subrutina.
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
1
#!/usr/local/bin/perl
$total = 0;
&getnumbers;
foreach $number (@numbers) {
$total += $number;
}
print ("El total es $total\n");
sub getnumbers {
11:
12:
13:
14: }
$line = <STDIN>;
$line =~ s/^\s+|\s*\n$//g;
@numbers = split(/\s+/, $line);
SALIDA
$ program9_1
11 8 16 4
El total es 39
$
ANALISIS
Líneas 10-14 son un ejemplo de una subrutina. La palabra reservada (keyword) sub le
dice al Intérprete de Perl que eso es una definición de una subrutina.
El getnumbers inmediatamente seguido al sub es el nombre de la subrutina; el
programa Perl usa ese nombre cuando invoca la subrutina.
El programa comienza su ejecución normal empezando por la línea 3. starts execution in
the normal way, beginning with la línea 3. La línea 4 invoca la subrutina getnumbers;
el carácter & le dice al Intérprete de Perl que el siguiente nombre es el nombre de la
subrutina. (Esto asegura que el Intérprete de Perl no confunda nombres de subrutina con
nombres de variables escalares o arreglos)
El Intérprete de Perl ejecuta la línea 4 bifurcando a la primera sentencia ejecutable
dentro de la subrutina, la cual es la línea 11. El intérprete entonces ejecuta las Líneas
11-13.
Las Líneas 11-13 crean el arreglo @numbers de la siguiente manera:
•
La línea 11 lee una línea de input desde el standard input file.
•
La línea 12 remueve los espacios iniciales y finales (incluído el newline) desde
la línea de input.
•
La línea 13 parte la línea de input en números y asigna el resultado a
@numbers.
Antes de que la línea 13 finalice, el Intérprete de Perl vuelve al main program y ejecuta
la línea inmediatamente siguiente a la llamada de la subrutina, la cual es la línea 5.
Las Líneas 5-7 suman los números usando la sentencia foreach para loopear la lista de
números almacenada en @numbers. (Ojo, el programa no chequea si son números, si
fueran otra cosa los convierte a cero)
La sintaxis para la definición de una subrutina es:
sub subname {
statement_block
}
subname es el nombre de la subrutina. Como todos los nombres en Perl, subname
consiste en un carácter alfabético seguido de una o más letras, dígitos o guiones (_). Es
aconsejable evitar nombres iguales al de una palabra reservada de perl, y no poner todo
el nombre con letras mayúsculas ya que así es como Perl llama a sus subrutinas internas.
2
statement_block es el cuerpo de la subrutina y consiste en una o mas sentencias Perl.
Cualquier sentencia que puede aparecer en un main program, puede aparecer en una
subrutina.
NOTA
El Intérprete de Perl nunca confunde un nombre de subrutina con el nombre de
una variable escalar o cualquier otro porque puede deducir del contexto cual
nombre estamos haciendo referencia. Pro lo tanto podemos tener una subrutina
y una variable escalar con el mismo nombre. Por ejemplo:
$word = 0;
&word;
Aquí, cuando el Intérprete de Perl ve el & en la segunda sentencia, asume que
esta llamando una subrutina llamada word.
Atención
Cuando se definen nombres de subrutinas, es conveniente no usar nombres
iguales a las funciones de librería de Perl para evitar errores involuntarios. Si
bien nosotros podemos definir una subrutina llamada split y el Intérprete de
Perl puede distinguir la invocación de la subrutina split de la función de
librería split, (porque el nombre de la subrutina está precedido por un &
cuando se invoca), es muy fácil olvidar tipear el & y caer en el error.
@words = &split(1, 2); # subrutina
@words = split(/\s+/, $line); # library function
Las subrutinas pueden aparecer en cualquier parte de un programa.
Listado 9.2. Un programa conteniendo una subrutina en el medio del main
program.
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
#!/usr/local/bin/perl
while (1) {
&readaline;
last if ($line eq "");
sub readaline {
$line = <STDIN>;
}
print ($line);
}
print ("FIN\n");
SALIDA
$ program9_2
Aquí esta la linea de input
Aquí esta la linea de input
^D
FIN
$
ANALISIS
Este programa lee lineas del std input file y las escribe en el standard output file.
La línea 4 llama la subrutina readaline. Cuando examina la subrutina, la encuentra
contenida entre las lineas 6 y 8. Ahí vemos que lee una línea y la asigna a la variable
escalar $line.
3
Cuando readaline termina, la ejecución del programa continúa en la línea 5. Cuando la
línea 5 es ejecutada, el programa saltea las sentencias correspondientes a la definición
de la subrutina y continúa en la línea 9. El código dentro de una subrutina nunca es
ejecutado directamente.
TIP
Si bien las subrutinas pueden aparecer en cualquier parte de un programa, es usual
definirlas al principio o al final de un programa. Esto lo hace mas “legible”.
FORWARD REFERENCES A SUBRUTINAS
Como vimos, el Intérprete de Perl usa el carácter & para indicar que viene una
subrutina.
En Perl 5 no es ne4cesrio el & antes del nombre en la invocación si la subrutina ya fue
definida. Ejemplo:
sub readaline {
$line = <STDIN>;
}
...
readaline;
Esto es porque el intérprete ya sabe que readaline es una subrutina.
Si escribimos todas las subrutinas hacia el final de un programa, entonces si debemos
preceder su invocación con el carácter & salvo que hagamos al principio una forward
reference de la misma:
sub readaline;
# forward reference
...
readaline;
...
sub readaline {
$line = <STDIN>;
}
El forward reference le dice al Intérprete de Perl que readaline es el nombre de una
subrutina. De esta manera no necesitamos adicionarle el & en la invocación.
Atención
Algunas veces si invocamos una subrutina sin el & no obtenemos el resultado
esperado, en estos casos aconsejamos usarlo.
Retornando un valor desde una Subrutina
Veamos nuevamente la subrutina getnumbers del Listado 9.1.
10: sub getnumbers {
11:
$line = <STDIN>;
12:
$line =~ s/^\s+|\s*\n$//g;
13:
@numbers = split(/\s+/, $line);
14: }
4
Si bien esta subrutina es util, tiene una seria limitación: sobreescribe el arreglo
@numbers (tambien sobrescribe $line). Esto puede traer problemas… Por ejemplo, si
consideramos lo siguiente:
@numbers = ("the", "a", "an");
&getnumbers;
print ("El valor de \@numbers es: @numbers\n");
Cuando la subrutina getnumbers es invocada, el valor de @numbers es sobreescrito.
Esto no resulta obvio cuando miramos el programa de arriba.
En torno a esto, podemos usar una propiedad de las subrutinas en Perl: el valor de la
última expresión evaluada por la subrutina es considerada automáticamente como el
valor de retorno (return value) de la subrutina. Por ejemplo, en la subrutina getnumbers
del Listado 9.1, la última expresión evaluada es:
@numbers = split(/\s+/, $temp);
El valor de esta expresión es la lista de números obtenida del splitting de la línea de
input. De esta manera, la lista de números es el valor de retorno de la subrutina.
Para ver como usar el valor de retorno de una subrutina, veamos el Listado 9.3, el cual
modifica las líneas 4 y 13 del listado 9.1 original para usar el valor de retorno de la
subrutina getnumbers.
Listado 9.3. Un programa que usa en una subrutina el return value.
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
#!/usr/local/bin/perl
$total = 0;
@numbers = &getnumbers; # así getnumbers retornará su valor en @numbers
foreach $number (@numbers) {
$total += $number;
}
print ("El total es $total\n");
sub getnumbers {
$line = <STDIN>;
$line =~ s/^\s+|\s*\n$//g;
split(/\s+/, $line);
# Este es el return value
}
SALIDA
$ program9_3
11 8 16 4
El total es 39
$
ANALISIS
La línea 4, nuevamente llama a la subrutina getnumbers, pero esta vez, el arreglo
@numbers es asignado a la lista de números leídos desde el standard input file; de esta
manera la asignación se hace en el cuerpo principal del programa, no en la subrutina,
esto lo hace mas fácil de seguir.
La otra diferencia está en la llamada a la función split de la línea 13. Ahora no se
asigna su resultado a @numbers. De hecho no se le asigna a nada, porque no es necesario
hacerlo.
5
La línea 13 es la última expresión evaluada en getnumbers, por eso automáticamente se
convierte en el valor de retorno de la subrutina.
De esta manera cuando en la línea 4 se llama a la subrutina getnumbers, el listado
retornado por el split es asignado a @numbers.
NOTA
Si la idea de la última expresión evaluada es confusa para Uds. No hay nada
malo en crear una variable dentro de la subrutina solo para contener el valor de
retorno. Por ejemplo:
sub getnumbers {
$line = <STDIN>;
$line =~ s/^\s+|\s*\n$//g;
@retval = split(/\s+/, $temp); # the return value
}
Aquí es obvio que el valor de retorno está contenido en @retval.
La desventaja está solo en usar una asignación cuando no es necesaria.
Eliminarla hace la subrutina mas eficiente. Usar una variable especial para
retornar valores elimina unos cuantos errores que veremos mas adelante.
Se puede usar el valor de retorno de una subrutina en cualquier parte de una expresión.
Por ejemplo:
foreach $number (&getnumbers) {
print ("$number\n");
}
Este foreach itera sobre la lista de números retornados por getnumbers. Cada
elemento de la lista es asignado a $number por turno, lo que produce la impresión de
todos los números de la lista.
VALORES DE RETORNO Y EXPRESIONES CONDICIONALES
Como el valor de retorno de una subrutina es siempre la última expresión evaluada, a
veces el valor de retorno no devuelve lo que esperamos.
Listado 9.5: Consideremos nuevamente el ejemplo del Listado 9.1, pero esta vez todo el
trabajo hecho dentro de una subrutina llamada get_total: se leen líneas del Standard
input file, luego se separa en números y los suma.
Listado 9.5. Un programa que ilustra un potencial problema con los valores de
retorno desde las subrutinas.
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
6
#!/usr/local/bin/perl
$total = &get_total;
print("El total es $total\n");
sub get_total {
$value = 0;
$inputline = <STDIN>;
$inputline =~ s/^\s+|\s*\n$//g;
@subwords = split(/\s+/, $inputline);
$index = 0;
while ($subwords[$index] ne "") {
$value += $subwords[$index++];
}
}
SALIDA
$ program9_5
11 8 16 4
El total es
$
ANALISIS
Obviamente que el propósito de Este programa es asignar el contenido de la variable
escalar $value a la variable escalar $total. Pero cuando la la línea 4 trata de imprimir
el total, el valor de $total está vacío. Que sucedió?
El problema en la subrutina get_total es que la última expresión evaluada no es la que
nosotros esperábamos sino la expresión condicional de la Línea 12.
$subwords[$index] ne ""
El loop de las Líneas 12-14 itera hasta que el valor de la expresión es 0. Cuando el valor
de la expresión es cero, el loop termina, y la subrutina también. Por lo tanto el 0 es lo
que retorna y como en un print el 0 se interpreta como string nulo, la línea 4 imprime lo
siguiente (lo cual no es lo que esperábamos)
El total es
Listado 9.6 muestra como solucionar este problema
Listado 9.6. Un programa que corrige el problema del 9.5
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
#!/usr/local/bin/perl
$total = &get_total;
print("El total es $total.\n");
sub get_total {
$value = 0;
$inputline = <STDIN>;
$inputline =~ s/^\s+|\s*\n$//g;
@subwords = split(/\s+/, $inputline);
$index = 0;
while ($subwords[$index] ne "") {
$value += $subwords[$index++];
}
$retval = $value;
}
SALIDA
$ program9_6
11 8 16 4
El total es 39.
$
ANALISIS
Este programa es igual al 9.5 excepto por el agregado de la línea 15: Esta línea asigna
el total almacenado en $value a la variable escalar $retval.
7
La línea 15 asegura que el valor de la última expresion evaluada en la subrutina
get_total contenga el total buscado. Luego la línea 3 efectúa una nueva asignación e
imprime.
Pero en realidad … no sería necesario efectuar la asignación a retval, la subrutina
get_total podría quedar como sigue y seguir siendo efectiva:
sub get_total {
$value = 0;
$inputline = <STDIN>;
$inputline =~ s/^\s+|\s*\n$//g;
@subwords = split(/\s+/, $inputline);
$index = 0;
while ($subwords[$index] ne "") {
$value += $subwords[$index++];
}
$value;
}
Aquí la última expresión evaluada es simplemente $value. El valor de esta expresión es
el valor corriente almacenado en $value, es decir la suma de los números de la línea.
TIP
Las subrutinas que dan su valor de retorno al final (como get_total en Listado
9.6) son conocidas como single-exit modules. Estas subrutinas salvan problemas
como los vistos en Listado 9.5, y normalmente son mucho más fáciles de leer. Por
estas razones es una muy buena idea definirlas así.
La Sentencia return
Otra manera de asegurar el valor de retorno de una subrutina es usando la sentencia
return . La sintaxis es la siguiente:
return (retval);
retval es el valor que queremos retornar. Puede ser un valor escalar (incluido el
resultado de una expresión) o una lista.
Listado 9.7 da un ejemplo de su uso
Listado 9.7. Un programa que usa la sentencia return
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
8
#!/usr/local/bin/perl
$total = &get_total;
if ($total eq "error") {
print ("No se ingresó nada.\n");
} else {
print("el total es $total.\n");
}
sub get_total {
$value = 0;
$inputline = <STDIN>;
$inputline =~ s/^\s+|\s*\n$//g;
if ($inputline eq "") {
return ("error");
}
@subwords = split(/\s+/, $inputline);
$index = 0;
19:
20:
21:
22:
23: }
while ($subwords[$index] ne "") {
$value += $subwords[$index++];
}
$retval = $value;
SALIDA
$ program9_7
^D
No se ingresó nada.
$
ANALISIS
Este programa es similar al Listado 9.6. La única diferencia de este programa es que
chequea si la línea de input existe.
Si la línea de input no existe, la expresión condicional en la línea 14 es verdadera, y la
línea 15 es ejecutada. La línea 15 sale de la subrutina con return value error; Luego
error se asigna a $total en la línea 3.
Este programa muestra también como es útil permitir almacenar en variables escalares
números o character strings. Cuando la subrutina get_total detecta el error, asigna un
valor no numérico a $total, lo que permite fácilmente determinar que algo anduvo
mal. En otros lenguajes, no se ofrece esta flexibilidad.
Usando variables locales en Subrutinas
La subrutina get_total en Listado 9.7 define algunas variables que solo se usan dentro
de la subrutina: El arreglo @subwords, y 4 variables escalares $inputline, $value,
$index, y $retval.
Si tenemos la certeza que estas variables solo serán usadas dentro de la subrutina,
podemos decirle a Perl que defina estas variables como locales (local variables).
En Perl 5, existen dos sentencias para definir local variables:
•
La sentencia my, la cual define variables que solo van a existir dentro de la
subrutina.
•
La sentencia local, la cual define variables que solo van a existir dentro de la
subrutina y cualquier otra subrutina llamada por esta (como hacer esto lo
veremos luego).
Listado 9.8 muestra como podemos usar my para definir variables que existan solo en la
subrutina.
Listado 9.8. Un programa que usa local variables.
1:
2:
3:
4:
5:
6:
7:
8:
9
#!/usr/local/bin/perl
$total = 0;
while (1) {
$linetotal = &get_total;
last if ($linetotal eq "done");
print ("Total para esta línea: $linetotal\n");
$total += $linetotal;
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
}
print ("Total para todas las Líneas: $total\n");
sub get_total {
my ($total, $inputline, @subwords);
my ($index, $retval);
$total = 0;
$inputline = <STDIN>;
if ($inputline eq "") {
return ("done");
}
$inputline =~ s/^\s+|\s*\n$//g;
@subwords = split(/\s+/, $inputline);
$index = 0;
while ($subwords[$index] ne "") {
$total += $subwords[$index++];
}
$retval = $total;
}
SALIDA
$ program9_8
11 8 16 4
Total para esta línea: 39
7 20 6 1
Total para esta línea: 34
^D
Total para todas las Líneas: 73
$
ANALISIS
Este programa usa dos copias de la variable escalar $total. Una copia de $total esta
definida en el main program y almacena el total de todas las Líneas.
La variable escalar $total está también definida en la subrutina get_total; en esta
subrutina, $total referencia al total para una linea en particular, y la línea 13 define
que ésta es una local variable. Como esta variable $total esta definida en la subrutina,
la copia de $total definida en el main program no se ve afectada por la línea 15 o 24.
Atención
Como la variable local no es conocida fuera de la subrutina, se destruye cuando
la subrutina es completada. Si la subrutina es llamada nuevamente una nueva
copia de la variable local es definida. El siguiente ejemplo muestra como NO
funcionan:
sub subrutina_count {
my($number_of_calls);
$number_of_calls += 1;
}
Esta subrutina no devuelve el numero de veces que la subrutina es llamada, ya
que cada vez que se la invoca, una nueva copia de $number_of_calls es
definida. Siempre devuelve 1.
Las variables locales pueden aparecer en cualquier parte de un programa, pero para dar
claridad en el código, es preferible ubicarlas al principio.
10
INICIALIZACIÓN DE VARIABLES LOCALES
Las variables locales pueden ser inicializadas. Ejemplo:
sub my_sub {
my($scalar) = 43;
my(@array) = ("here's", "a", "list");
# code goes here
}
Aqui la variable local $scalar toma un valor inicial de 43, y el arreglo @array es
inicializado con la lista ("here's", "a", "list").
Pasando valores a una Subrutina
Podemos hacer mas flexibles nuestras subrutinas si permitimos que ellas acepten
valores pasados desde el main program. Estos valores se los llama Argumentos.
Listado 9.9 provee un simple ejemplo de una subrutina que acepta tres argumentos
Listado 9.9. Un programa que usa una subrutina to print three numbers and their
total.
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
#!/usr/local/bin/perl
print ("Ingrese 3 numeros, uno por vez:\n");
$number1 = <STDIN>;
chop ($number1);
$number2 = <STDIN>;
chop ($number2);
$number3 = <STDIN>;
chop ($number3);
&printnum ($number1, $number2, $number3);
sub printnum {
my($number1, $number2, $number3) = @_;
my($total);
print ("Los numeros ingresados son: ");
print ("$number1 $number2 $number3\n");
$total = $number1 + $number2 + $number3;
print ("El total es: $total\n");
}
SALIDA
$ program9_9
Ingrese 3 numeros, uno por vez:
5
11
4
Los numeros ingresados son: 5 11 4
El total es: 20
$
ANALISIS
La línea 10 llama a la subrutina printnum. Tres argumentos son pasados a printnum,
los valores almacenados en: $number1, $number2, y $number3. Notar que estos
argumentos son pasados a la subrutina en la misma forma que se pasan a las built-in
library functions.
11
La línea 13 define copias locales de las variables escalares $number1, $number2, y
$number3 al mismo tiempo que asigna el contenido de la variable de sistema @_.
@_ es creada cada vez que una subrutina es llamada con argumentos. Contiene una lista
con los argumentos en el orden en el cual fueron pasados. En este caso, @_ contiene la
lista (5, 11, 4).
La asignación de la línea 13 trabaja igual que siempre: el primer elemento de la lista, 5,
es asignado a la primera variable, $number1; el segundo, 11, es asignado a $number2; y
finalmente, 4, es asignado a $number3.
NOTA
Después que la variable @_ es creada, puede ser usada dentro de la subrutina
como cualquier arreglo. La siguiente subrutina es equivalente a las Líneas 12-19
de Listado 9.9:
sub printnum {
my($total);
print ("The numbers you entered: ");
print ("$_[0] $_[1] $_[2]\n");
$total = $_[0] + $_[1] + $_[2];
print ("The total: $total\n");
}
Aquí, $_[0] referencia al primer elemento del arreglo @_, $_[1] referencia al
Segundo elemento, y $_[2] referencia al tercero.
Esta subrutina es mas eficiente, pero mas difícil de escribir y leer.
TIP
Usualmente es mejor definir variables locales y asignar @_ a ellas para que así
sea mas fácil de entender el código.
Listado 9.10 es otro ejemplo de un programa que pasa argumentos a una subrutina. Este
programa usa la misma subrutina para contar el numero de palabras y el numero de
caracteres que recibe por STDIN.
Listado 9.10. Otro ejemplo de una subrutina con argumentos pasados.
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
12
#!/usr/local/bin/perl
$wordcount = $charcount = 0;
$charpattern = "";
$wordpattern = "\\s+";
while ($line = <STDIN>) {
$charcount += &count($line, $charpattern);
$line =~ s/^\s+|\s+$//g;
$wordcount += &count($line, $wordpattern);
}
print ("Total: $wordcount palabras, $charcount caracteres\n");
sub count {
my ($line, $pattern) = @_;
my ($count);
if ($pattern eq "") {
@items = split (//, $line);
} else {
@items = split (/$pattern/, $line);
}
$count = @items;
}
SALIDA
$ program9_10
Esta es la línea de input.
Aqui hay otra linea.
^D
Total: 10 palabras, 46 caracteres
$
PASANDO UNA LISTA A UNA SUBRUTINA
Si queremos pasar una lista a una subrutina veamos el siguiente ejemplo:
La siguiente subrutina suma los elementos de una lista e imprime el resultado
sub addlist {
my (@list) = @_;
$total = 0;
foreach $item (@list) {
$total += $item;
}
print ("The total is $total\n");
}
Invocaciones ejemplo:
&addlist (@mylist);
&addlist ("14", "6", "11");
&addlist ($value1, @sublist, $value2);
En cada caso, los valores son juntados en una sola lista, y pasados como una lista simple
a addlist.
Como los valores son juntados, entonces solo se debe incluir una lista en los argumentos
de una sub y es conveniente ponerla COMO ULTIMO ARGUMENTO
La subrutina:
sub twolists {
my (@list1, @list2) = @_;
}
No es útil porque las dos listas se juntan y SIEMPRE la se asigna la lista vacía a
@list2, ya que @list1 absorbe TODO el contenido de @_.
Otro Ejemplo:
sub twoargs {
my ($scalar, @list) = @_;
}
Invocación:
&twoargs(47, @mylist);
13
EL VALOR 47 es asignado a $scalar, y @mylist es asignado a @list.
Si queremos podemos invocar a twoargs con una lista simple como sigue:
&twoargs(@mylist);
Con el mismo resultado que antes, el primer elemento de la lista se asigna a $scalar, y
el resto a @list.
Llamando Subrutinas desde otras Subrutinas
En Perl, podemos llamar subrutinas desde otra subrutina. Para hacerlo, se usa la misma
sintaxis que vinimos empleando.
Las Subrutinas que son llamadas desde otras subrutinas se las conoce como nested
subrutinas
Listado 9.11. Ejemplo de nested
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
#!/usr/local/bin/perl
($wordcount, $charcount) = &getcounts(3);
print ("Totals for three lines: ");
print ("$wordcount words, $charcount characters\n");
sub getcounts {
my ($numLines) = @_;
my ($charpattern, $wordpattern);
my ($charcount, $wordcount);
my ($line, $linecount);
my (@retval);
$charpattern = "";
$wordpattern = "\\s+";
$linecount = $charcount = $wordcount = 0;
while (1) {
$line = <STDIN>;
last if ($line eq "");
$linecount++;
$charcount += &count($line, $charpattern);
$line =~ s/^\s+|\s+$//g;
$wordcount += &count($line, $wordpattern);
last if ($linecount == $numLines);
};
@retval = ($wordcount, $charcount);
}
sub count {
my ($line, $pattern) = @_;
my ($count);
if ($pattern eq "") {
@items = split (//, $line);
} else {
@items = split (/$pattern/, $line);
}
$count = @items;
}
SALIDA
$ program9_11
This is a line of input.
Here is another line.
14
Here is the last line.
Totals for three Lines: 15 words, 70 characters
15
Subrutinas Predefinidas
Perl considera las subrutinas cuyo nombre está todo en mayúsculas como parte del
núcleo, y son llamadas automáticamente por el sistema
•
BEGIN subrutina, se llama ANTES que cualquier sentencia. Es más, se ejecuta
ANTES que los script regulares sean analizados.
•
END subrutina, se llama ANTES que termine el script regular, al mismo tiempo
que sale del intérprete de perl
•
AUTOLOAD subrutina, se carga si hacemos una llamada a una subrutina
inexistente. La variable $AUTOLOAD contiene el nombre de la sub que dio
error, la variable @_ contiene la información pasada en la rutina que dio error.
Ejemplo de BEGIN
BEGIN {
print("Hi! Welcome to Perl!\n");
}
Cuando comienza la ejecución del script aparece:
Hi! Welcome to Perl!
Ejemplo de END
END {
print("Thank you for using Perl!\n");
}
El código de la subrutina END SIEMPRE se ejecuta, salvo aún si el programa termina
con die. Por ejemplo:
die("Prepare to die!\n");
END {
print("Ha! You can't kill me!\n");
}
Salida:
Prepare to die!
Ha! You can't kill me!
16
NOTA
Se pueden definer varias subrutinas END, en ese caso, se ejecutan
en el orden inverso de apariencia (la ultima se ejecuta primero)
AUTOLOAD
Se carga si hacemos una llamada a una subrutina inexistente. La variable
$AUTOLOAD contiene el nombre de la sub que dio error, la variable @_ contiene la
información pasada en la rutina que dio error. Ejemplo:
Listado 9.15. Un programa que usa AUTOLOAD.
1: #!/usr/local/bin/perl
2:
3: &nothere("hi", 46);
4:
5: AUTOLOAD {
6:
print("subrutina $AUTOLOAD not found\n");
7:
print("arguments passed: @_\n");
8: }
SALIDA
$ program9_15
subrutina main::nothere not found
arguments passed: hi 46
$
TIP
AUTOLOAD es útil para organizar el Programa Perl en módulos
17
QUE ESTA MAL?
1. #!/usr/local/bin/perl
for ($count = 1; $count <= 10; $count++) {
&print_ten ($count);
}
sub print_ten {
local ($multiplier) = @_;
for ($count = 1; $count <= 10; $count++) {
$printval = $multiplier * 10 + $count;
print ("$printval\n");
}
}
2. #!/usr/local/bin/perl
$line = <STDIN>;
@words = split(/\s+/, $line);
$searchword = <STDIN>;
&search_for_word (@words, $searchword);
sub search_for_word {
local (@searchlist, $searchword) = @_;
foreach $word (@searchlist) {
return (1) if ($word eq $searchword);
}
$retval = 0;
}
3. #!/usr/local/bin/perl
$line = <STDIN>;
@words = &split_la línea($line);
print ("@words\n");
sub split_la línea {
local ($line) = @_;
local (@words);
@words = split(/\s+/, $line);
if (@words == 0) {
@words = ("empty list");
}
}
18
Descargar