Perl ofrece un sistema llamado prototipos subrutina que le permiten escribir submarinos usuario que consiguen evalúan de manera similar a las funciones incorporadas. Los editores que desea emular son map
, grep
o sort
, que cada uno puede tomar un bloque como primer argumento.
de hacer eso con los prototipos, se utiliza sub name (&) {...}
donde el &
dice Perl que el primer argumento de la función es o bien un bloque (con o sin sub
), o una subrutina literal \&mysub
. El prototipo (&)
especifica uno y solo un argumento, si necesita pasar varios argumentos después del bloque de código, puede escribirlo como (&@)
, lo que significa un bloque de código seguido de una lista.
sub higher_order_fn (&@) {
my $code = \&{shift @_}; # ensure we have something like CODE
for (@_) {
$code->($_);
}
}
Esa subrutina ejecutará el bloque pasado en cada elemento de la lista pasada. El \&{shift @_}
parece un poco críptico, pero lo que hace es quitar el primer elemento de la lista, que debería ser un bloque de código. El &{...}
elimina la referencia del valor como una subrutina (invocando cualquier sobrecarga), y luego el \
toma inmediatamente la referencia al mismo. Si el valor fue una REF del CÓDIGO, entonces se devuelve sin cambios. Si se trataba de un objeto sobrecargado, se convierte en código. Si no se puede forzar a CODE, se produce un error.
para llamar a esta subrutina, usted escribiría:
higher_order_fn {$_ * 2} 1, 2, 3;
# or
higher_order_fn(sub {$_ * 2}, 1, 2, 3);
El (&@)
prototipo que permite escribir el argumento como una map
/grep
como el bloqueo sólo funciona cuando se utiliza la función de orden superior como una función. Si lo está utilizando como un método, debe omitir el prototipo y escribirlo de esta manera:
sub higher_order_method {
my $self = shift;
my $code = \&{shift @_};
...
$code->() for @_;
}
...
$obj->higher_order_method(sub {...}, 'some', 'more', 'args', 'here');
En general, los prototipos de función no son necesarios y considero que son un poco inútiles. – jiggy
@jiggy ¿Puedes elaborar un poco, por favor? –
=> En este caso, usar el prototipo '($)' puede no significar lo que piensas que significa. Significa "darme un argumento", pero también significa "imponer un contexto escalar en ese argumento". Entonces, si tuvieras una matriz con un elemento y se llamara 'foo_1 @ array', entonces 'foo_1' pasaría el número' 1', que es el recuento de los elementos en la matriz. Para obtener realmente el primer argumento, necesitarás llamarlo como 'foo_1 $ array [0]'. Si no tenía el prototipo, podría haberlo llamado 'foo_1 @ array' y habría funcionado correctamente. –