web-dev-qa-db-fra.com

Comment exécuter une fonction anonyme en Perl?

(sub {
print 1;
})();



sub {
print 1;
}();

J'ai essayé de différentes manières, tout va mal ...

29
asker

(sub { ... }) vous donnera le pointeur sur la fonction, vous devez donc appeler par référence.

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

L’autre méthode simple, comme indiqué par Blagovest Buyukliev serait de déréférencer le pointeur de la fonction et d’appeler cela à l’aide des opérateurs { }.

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

38
zellio

Oui, je ne m'attendais pas à ce que vous proposiez autant de possibilités. Mais vous avez raison, c'est Perl et TIMTOWTDI : +1 pour la créativité!

Mais pour être honnête, j’utilise à peine une autre forme que celle-ci:

La syntaxe de base

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

# ...

$greet->( 'asker' )

C'est assez simple: sub {} renvoie une référence à une sous-routine, que vous pouvez stocker et transmettre comme n'importe quel autre scalaire. Vous pouvez ensuite l'appeler par déréférencement. Il existe également une deuxième syntaxe pour déréférencer: &{ $sub }( 'asker' ), mais je préfère personnellement la syntaxe de flèche, parce que je la trouve plus lisible et qu’elle s’aligne à peu près sur le hachage de déréférencement $hash->{ $key } et les tableaux $array->[ $index ]. Vous trouverez plus d’informations sur les références dans perldoc perlref .

Je pense que les autres exemples donnés sont un peu avancés, mais pourquoi ne pas les regarder:

Aller à

sub bar {goto $foo};
bar;

Rarement vu et beaucoup craint ces jours-ci. Mais au moins, c'est un goto &function, qui est considéré moins nocif que ses amis tordus: goto LABEL ou goto EXPRESSION (ils sont obsolètes depuis le 5.12 et déclenchent un avertissement). Dans certaines circonstances, vous souhaitez utiliser ce formulaire, car il ne s'agit pas d'un appel de fonction habituel. La fonction appelante (bar dans l'exemple donné) n'apparaîtra pas dans la pile d'appels. Et vous ne transmettez pas vos paramètres, mais le @_ actuel sera utilisé. Regardez ça:

use Carp qw( cluck );

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


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

invisible( 'real' );

Sortie:

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

Et il n'y a aucune trace d'une fonction invisible dans la trace de la pile. Plus d'infos sur goto dans perldoc -f goto .

Appels de méthode

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

Si vous appelez une méthode sur un objet, le premier paramètre transmis à cette méthode sera l'invocant (généralement une instance ou le nom de la classe). Ai-je déjà dit 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

L'extrait ci-dessus contient deux appels qui ne fonctionneront pas, car Perl essaiera de trouver une méthode appelée ask dans le package asker (en fait, cela fonctionnerait si ce code était dans ledit paquet). Mais le troisième réussit, car vous donnez déjà la bonne méthode à Perl et il n’est pas nécessaire de la rechercher. Comme toujours: plus d'informations dans le perldoc Je ne trouve aucune raison pour le moment, pour excuser cela dans le code de production.

Conclusion

Au départ, je n'avais pas l'intention d'écrire autant, mais j'estime qu'il est important de disposer de la solution commune au début d'une réponse et de quelques explications sur les constructions inhabituelles. J'admets être un peu égoïste ici: chacun d'entre nous pourrait finir par conserver le code de quelqu'un, qui a trouvé cette question et n'a fait que copier l'exemple le plus élevé.

26
Egga Hartung

Dans Perl, il n’est pas vraiment nécessaire d’appeler un sous-programme anonyme dans lequel il est défini. En général, vous pouvez réaliser tout type de délimitation dont vous avez besoin avec des blocs nus. Le cas d'utilisation qui me vient à l'esprit est de créer un tableau avec alias:

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

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

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

Sinon, vous stockerez généralement un sous-programme anonyme dans une structure de variable ou de données. Les styles d'appel suivants fonctionnent avec une déclaration de variable et une déclaration sub {...}:

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

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

si vous avez le coderef dans un scalaire, vous pouvez également l'utiliser comme méthode pour les valeurs normales et bénies.

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], ...)
12
Eric Strom

Je suis sans cesse amusé de trouver le moyen d'appeler des fonctions anonymes:

$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

et bien sûr, l'évidence:

&$foo();
$foo->();
5
Alex

Vous avez besoin d'un opérateur de flèche:

(sub { print 1;})->();
4
Foo Bah

Vous n'aurez peut-être même pas besoin d'une fonction anonyme si vous souhaitez exécuter un bloc de code et qu'il n'y ait aucune ou une entrée. Vous pouvez utiliser map à la place.

Juste pour l'effet secondaire:

map { print 1 } 1;

Transformer les données, prenez soin d’assigner à une liste:

my ($data) = map { $_ * $_ } 2;
0
SzG