2009-08-21 5 views
2

Comment est-ce que j'écrirais une fonction qui accepte quelque chose comme la fonction de carte fait?Comment puis-je transmettre une fonction à un sous-Perl?

Exemple:

$func = sub { print $_[0], "hi\n" }; 
&something($f); 
sub something 
{ 
    my $func = shift; 
    for ($i = 0; $i < 5; $i++) 
    { $func->($i); } 
} 

fonctionne très bien.

mais si je l'ai fait

&something({ print $_[0], "hi\n" }); 

il ne sera pas le travail et dit func est une référence non définie.

Donc ma question serait comment j'écrirais une fonction qui accepte des paramètres comme la fonction de carte de Perls?

map { s/a/b/g } @somelist; 

Répondre

17

La fonction map a une syntaxe très magique, et vous ne voulez probablement pas de le copier, sauf si vous avez une très bonne raison; il suffit d'utiliser un sous régulière anonyme, comme ceci:

something(sub { print $_[0], "hi\n" }); 

Si vous voulez vraiment faire cela, cependant, vous devez utiliser un prototype:

sub my_map (&@) { 
    my ($func, @values) = @_; 
    my @ret; 
    for (@values) { 
     push @ret, $func->($_); 
    } 
    return @ret; 
} 

my @values = my_map { $_ + 1 } qw(1 2 3 4); 
print "@values"; # 2 3 4 5 

(Notez que $_ est portée dynamique, donc quelle que soit la valeur qu'il a dans l'appelant est conservé dans la fonction.)

List::Util et List::MoreUtils faire ce genre de chose beaucoup à créer des fonctions qui intégrées et semblent agir comme des variantes de map/grep. C'est vraiment le seul cas où quelque chose comme ça devrait être utilisé.

+0

+1. J'aime l'idée de localiser $ _ avec l'instruction "for" - permet aux fonctions 1-arg d'être belles et concises. (Et je suppose que vous pourriez "local ($ a, $ b);" pour 2-arg funcrefs a la sort().) –

1
&something({ print $_[0], "hi\n" }); 
#   ^^^ this isn't a reference 

&something(sub { print $_[0], "hi\n" }); # works just fine 
+0

Pourquoi avez-vous '' et sur le front? –

+0

Vraisemblablement parce que l'OP en avait un et la réponse copiait le style d'OP. Même si le préfixe & ne devrait probablement pas être là, comme l'a expliqué Sinan Ünür. –

6

Tout d'abord, n'utilisez pas & lorsque vous appelez sub s. De perldoc perlsub:

Les sous-programmes peuvent être appelés de manière récursive. Si un sous-programme est appelé en utilisant le formulaire &, la liste d'arguments est facultative et, si elle est omise, aucun tableau @_ n'est configuré pour le sous-programme: le tableau @_ au moment de l'appel est visible à la sous-routine à la place. C'est un mécanisme d'efficacité que les nouveaux utilisateurs pourraient souhaiter éviter.

Si vous voulez être en mesure passe un bloc simple pour « sub something », vous devez utiliser un prototype comme dans:

sub something(&@); 

# later 

sub something(&@) { 
    my ($coderef, @args) = @_; 

} 

Voir Prototypes.

Personnellement, je simplement passer une sous-référence explicite:

something(sub { }); 
Questions connexes