Funciones
## Objetivos de Aprendizaje
- Crear y llamar funciones (subrutinas)
- Pasar parametros y valores de retorno
- Comprender wantarray para contexto
- Dominar closures y funciones anonimas
- Usar funciones con prototipos
## Subrutinas
### Declaracion
```perl
use strict;
use warnings;
sub saludar {
print "Hola!\n";
}
saludar(); # Llamar la subrutina
```
### Nomenclatura
```perl
sub decir_hola { }
sub decir_hola_mundo { }
sub con_guion_bajo { }
sub mixedCase { } # La convencion de Perl es snake_case
```
### Llamando
```perl
# Con parentesis
saludar();
saludar;
# Con argumentos
saludar("Alice");
saludar "Alice"; # Sin parentesis
```
## Parametros
### Arreglo @_
```perl
use strict;
use warnings;
sub saludar {
my ($nombre) = @_; # Desempaquetar parametros
print "Hola, $nombre!\n";
}
saludar("Alice"); # Hola, Alice!
```
### Multiples Parametros
```perl
sub sumar {
my ($a, $b) = @_;
return $a + $b;
}
print sumar(5, 3); # 8
```
### Parametros Flexibles
```perl
sub sumar {
my $total = 0;
foreach my $val (@_) {
$total += $val;
}
return $total;
}
print sumar(1, 2, 3, 4, 5); # 15
```
### Parametros Nombrados
```perl
sub crear_usuario {
my %params = @_;
my $nombre = $params{nombre} // "Anonimo";
my $edad = $params{edad} // 0;
return { nombre => $nombre, edad => $edad };
}
my $usuario = crear_usuario(nombre => "Alice", edad => 30);
```
### Parametros por Defecto
```perl
sub saludar {
my ($nombre, $saludo) = @_;
$saludo //= "Hola";
print "$saludo, $nombre!\n";
}
saludar("Alice"); # Hola, Alice!
saludar("Bob", "Hola"); # Hola, Bob!
```
## Valores de Retorno
### Return explicito
```perl
sub max {
my ($a, $b) = @_;
if ($a > $b) {
return $a;
}
return $b;
}
print max(5, 3); # 5
```
### Return Implicito
```perl
sub obtener_valores {
my @valores = (1, 2, 3);
return @valores; # Contexto de lista
}
my @nums = obtener_valores(); # (1, 2, 3)
sub obtener_primero {
my ($a, $b) = @_;
$a; # Ultima expresion retornada
}
my $primero = obtener_primero(5, 3); # 5
```
### Retornar Multiples Valores
```perl
sub dividir {
my ($a, $b) = @_;
return (int($a / $b), $a % $b);
}
my ($cociente, $residuo) = dividir(10, 3);
print "C: $cociente, R: $residuo\n"; # C: 3, R: 1
```
## Conciencia de Contexto
### wantarray
```perl
sub obtener_valores {
if (wantarray) {
return ("contexto", "lista");
} elsif (defined wantarray) {
return "escalar";
} else {
return "void";
}
}
my @lista = obtener_valores(); # "contexto lista"
my $escalar = obtener_valores(); # "escalar"
obtener_valores(); # "void"
```
### Ejemplo Practico
```perl
sub obtener_datos {
my @datos = (1, 2, 3);
if (wantarray) {
return @datos;
}
return \@datos; # Retornar referencia en contexto escalar
}
my @lista = obtener_datos(); # Lista
my $ref = obtener_datos(); # Referencia
```
## Pasando Referencias
### Referencias de Arreglo
```perl
sub procesar_arreglo {
my ($arr_ref) = @_;
foreach my $elem (@$arr_ref) {
print "$elem ";
}
print "\n";
}
my @nums = (1, 2, 3);
procesar_arreglo(\@nums);
```
### Referencias de Hash
```perl
sub procesar_hash {
my ($hash_ref) = @_;
foreach my $clave (keys %$hash_ref) {
print "$clave => $hash_ref->{$clave}\n";
}
}
my %datos = (a => 1, b => 2);
procesar_hash(\%datos);
```
### Modificar Original
```perl
sub duplicar_valores {
my ($arr_ref) = @_;
for my $i (0 .. $#$arr_ref) {
$arr_ref->[$i] *= 2;
}
}
my @nums = (1, 2, 3);
duplicar_valores(\@nums);
print "@nums\n"; # 2 4 6
```
## Closures
### Closure Basico
```perl
use strict;
use warnings;
sub crear_contador {
my $contador = 0;
return sub {
$contador++;
return $contador;
};
}
my $contador = crear_contador();
print $contador->(); # 1
print $contador->(); # 2
print $contador->(); # 3
my $contador2 = crear_contador();
print $contador2->(); # 1 (contador separado)
```
### Funcion de Fabrica
```perl
sub multiplicador {
my ($factor) = @_;
return sub {
my ($num) = @_;
return $num * $factor;
};
}
my $doble = multiplicador(2);
my $triple = multiplicador(3);
print $doble->(5); # 10
print $triple->(5); # 15
```
### Variables de Estado (Perl 5.10+)
```perl
use strict;
use warnings;
use 5.010;
sub contador {
state $contador = 0; # Estado persistente
return ++$contador;
}
print contador(); # 1
print contador(); # 2
print contador(); # 3
```
## Funciones Anonymous
### Closures como Callbacks
```perl
use strict;
use warnings;
my @numeros = (1, 2, 3, 4, 5);
my @cuadrados = map { $_ * $_ } @numeros;
print "@cuadrados\n"; # 1 4 9 16 25
my @pares = grep { $_ % 2 == 0 } @numeros;
print "@pares\n"; # 2 4
```
### Subrutina Anonymous
```perl
my $sumar = sub {
my ($a, $b) = @_;
return $a + $b;
};
print $sumar->(5, 3); # 8
# O con desreferenciacion
print &{ $sumar }(5, 3); # 8
```
## Prototipos
### Prototipos Basicos
```perl
use strict;
use warnings;
sub mi_print($$) { # Espera dos escalares
my ($str1, $str2) = @_;
print $str1, $str2;
}
mi_print("Hola", " Mundo");
```
### Caracteres de Prototipo
| Caracter | Significado |
|----------|-------------|
| `$` | Escalar |
| `@` | Arreglo |
| `%` | Hash |
| `&` | Subrutina |
| `*` | Typeglob |
| `\` | Referencia |
### Problemas con Prototipos
```perl
# Los prototipos no funcionan con llamadas a metodos
# y pueden ser confusos. Usar con precauccion.
# Mejor: parametros explicitos
sub sumar {
my ($a, $b) = @_;
return $a + $b;
}
```
## Variables Especiales en Subrutinas
### Detalles de @_
```perl
sub inspeccionar_args {
print "Numero de args: ", scalar(@_), "\n";
foreach my $i (0 .. $#_) {
print " Arg $i: $_[$i]\n";
}
}
inspeccionar_args(1, "hola", 3.14);
```
### Shift
```perl
sub procesar {
my $primero = shift; # Primer elemento
my $segundo = shift; # Segundo elemento
my @resto = @_; # Elementos restantes
}
```
## Recursion
```perl
sub factorial {
my ($n) = @_;
return 1 if $n <= 1;
return $n * factorial($n - 1);
}
print factorial(5); # 120
# Version iterativa
sub factorial_iter {
my ($n) = @_;
my $resultado = 1;
for my $i (2 .. $n) {
$resultado *= $i;
}
return $resultado;
}
```
## Resumen
- Subrutinas definidas con `sub nombre { }`
- Parametros pasados via arreglo `@_`
- Usa `my` para localizary desempquetar parametros
- Valores de retorno con `return` o ultima expresion implicita
- `wantarray` verifica el contexto de llamada
- Los closures capturan variables lexicas
- Subrutinas anonimas con `sub { }`
- Referencias pasadas para arreglos/hashes a modificar
- Variables `state` persisten entre llamadas (5.10+)
- Los prototipos son opcionales y pueden ser problematicos
Comments
Comments powered by Giscus
To enable comments, add your Giscus embed code here.
Learn more about Giscus →