2011-09-08 9 views

Respuesta

35

(sub { ... }) le dará el puntero a la función por lo que debe llamar a modo de referencia.

(sub { print "Hello world\n" })->();

El otro método fácil, como ha señalado Blagovest Buyukliev sería la de eliminar la referencia al puntero de función y llamar a que el uso de los operadores { }

&{ sub { print "Hello World" }}();

+0

Eso debería ser '& {sub {print "Hello World"}} () '. Sin los parens, es una llamada muy especial. – ikegami

+0

tan cierto ikegami - fijo – zellio

+0

@ikegami: ¿qué quiere decir con 'una llamada muy especial'? ¿Por qué no puedes dejar los paréntesis afuera? –

4

Es necesario operador de flecha:

(sub { print 1;})->(); 
5

estoy infinitamente divertido por la búsqueda de formas para llamar a funciones anónimas:

$foo = sub {say 1}; 

sub bar {goto $foo}; 
bar; 

''->$foo; # technically a method, along with the lovely: 

undef->$foo; 

() = sort $foo 1,1; # if you have only two arguments 

y, por supuesto, lo que es obvio:

&$foo(); 
$foo->(); 
11

No hay mucha necesidad en Perl para llamar a una subrutina anónima donde se define. En general, puede lograr cualquier tipo de alcance que necesite con bloques desnudos. El caso de una utilización que viene a la mente es la creación de una serie de alias:

my $alias = sub {\@_}->(my ($x, $y, $z)); 

$x = $z = 0; 
$y = 1; 

print "@$alias"; # '0 1 0' 

De lo contrario, que se suele almacenar una subrutina anónima en una estructura variable o datos. Los siguientes estilos de llamadas de trabajo tanto con una variable y una declaración sub {...}:

dereference arrow: sub {...}->(args) or $code->(args) 

dereference sigil: &{sub {...}}(args) or &$code(args) 

si usted tiene la coderef en un escalar, también se puede utilizar como un método en valores regulares y bendito.

my $method = sub {...}; 

$obj->$method   # same as $method->($obj) 
$obj->$method(...)  # $method->($obj, ...) 

[1, 2, 3]->$method  # $method->([1, 2, 3]) 
[1, 2, 3]->$method(...) # $method->([1, 2, 3], ...) 
+1

'sub {} ->()', 'do {}' y '{}' tienen propiedades diferentes. Colocaría 'sub {} ->()' más cerca de 'do {}', no '{}'. – ikegami

22

Yay, no esperaba que tu gente presentara tantas posibilidades. Pero tienes razón, esto es perl y TIMTOWTDI: +1 para creativitiy!

Pero para ser honesto, yo uso casi otra forma que lo siguiente:

El básico Sintaxis

my $greet = sub { 
    my ($name) = @_; 
    print "Hello $name\n"; 
}; 

# ... 

$greet->('asker') 

Es bastante sencillo: sub {} devuelve una referencia a una sub-rutina, que puede almacenar y pasar como cualquier otro escalar. Puede llamarlo desreferenciando. También existe una segunda sintaxis para la desreferencia: &{ $sub }('asker'), pero personalmente prefiero la sintaxis de flecha, porque la encuentro más legible y se alinea con los algoritmos hash de desreferenciación $hash->{ $key } y los arrays $array->[ $index ]. Se puede encontrar más información sobre referencias en perldoc perlref.

creo que los otros ejemplos dados son un poco más avanzado, pero ¿por qué no echar un vistazo a ellos:

Goto

sub bar {goto $foo}; 
bar; 

pocas veces visto y temidas en estos días.Pero al menos es goto &function, que se considera menos dañino que sus amigos corruptos: goto LABEL o goto EXPRESSION (están en desuso desde 5.12 y generan una advertencia). En realidad, hay algunas circunstancias en las que desea utilizar ese formulario, porque esta no es una llamada de función habitual. La función de llamada (bar en el ejemplo dado) no aparecerá en la pila de llamadas. Y no pasa sus parámetros, pero se usará el actual @_. Echar un vistazo a esto:

use Carp qw(cluck); 

my $cluck = sub { 
    my ($message) = @_; 
    cluck $message . "\n"; 
}; 


sub invisible { 
    @_ = ('fake'); 
    goto $cluck; 
} 

invisible('real'); 

Salida:

fake at bar.pl line 5 
    main::__ANON__('fake') called at bar.pl line 14 

Y no hay ningún indicio de una función invisible en el seguimiento de la pila. Más información sobre goto en perldoc -f goto.

Método Llamadas

''->$foo; 
# or 
undef->$foo; 

Si se llama a un método en un objeto, el primer parámetro pasado a este método será el invocaciones (por lo general una instancia o el nombre de la clase). ¿Ya dije que TIMTOWTCallAFunction?

# this is just a normal named sub 
sub ask { 
    my ($name, $question) = @_; 
    print "$question, $name?\n"; 
}; 

my $ask = \&ask; # lets take a reference to that sub 

my $question = "What's up"; 

'asker'->ask($question); # 1: doesn't work 

my $meth_name = 'ask'; 
'asker'->$meth_name($question); # 2: doesn't work either 

'asker'->$ask($question); # 1: this works 

En el fragmento anterior son dos llamadas, que no va a funcionar, porque Perl tratarán de encontrar un método llamado ask en el paquete asker (en realidad funcionaría si ese código se encontraba en dicho paquete). Pero el tercero tiene éxito, porque ya le das a Perl el método correcto y no necesita buscarlo. Como siempre: más información en el perldoc No puedo encontrar ninguna razón en este momento, para disculpar esto en el código de producción.

Conclusión

Al principio yo no tenía la intención de escribir mucho, pero creo que es importante tener la solución común al inicio de una respuesta y algunas explicaciones a las construcciones inusuales. Admito ser un poco egoísta aquí: cada uno de nosotros podría terminar manteniendo el código de alguien, que encontró esta pregunta y simplemente copió el mejor ejemplo.

+3

+1 por coraje; cada vez que doy mi tiempo para escribir respuestas como esta, me molestan los camiones con votos hacia abajo que contienen ... demasiado tiempo ... o ... nadie quiere pasar tanto tiempo leyendo esto ... así que lo pondré en este +1 solo en caso de que te golpee un camión. (y cualquier otra persona que lo haya hecho) – osirisgothra

+1

@osirisgothra gracias por las lindas palabras. la respuesta tiene casi cuatro años, y no hay camiones hasta el momento: -D –

+2

Los programadores a los que no se les puede molestar leer son vagos de mala manera, no de la mejor manera.Básicamente no están lejos del trabajo "haz mi trabajo [doméstico] para mí, así puedo ir [a la playa | a casa temprano]". –

0

Es posible que ni siquiera necesite una función anónima si desea ejecutar un bloque de código y hay cero o una entrada. Puede usar map en su lugar.

Sólo por el efecto secundario:

map { print 1 } 1; 

transformar los datos, tenga cuidado para asignar a una lista:

my ($data) = map { $_ * $_ } 2; 
Cuestiones relacionadas