2009-08-21 13 views
2

Wie würde ich eine Funktion schreiben, die so etwas wie die Kartenfunktion akzeptiert?Wie kann ich eine Funktion an ein Perl Sub übergeben?

Beispiel:

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

gut funktioniert.

aber dann, wenn ich tat

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

es wird nicht funktionieren und sagt func eine undefinierte Referenz.

Also meine Frage wäre, wie würde ich eine Funktion schreiben, die Parameter wie Perls Kartenfunktion akzeptiert?

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

Antwort

17

Die map Funktion hat eine sehr magische Syntax, und Sie wahrscheinlich nicht wollen, um es zu kopieren, wenn Sie einen wirklich guten Grund haben; benutzen Sie einfach eine regelmäßige anonyme Unter, wie folgt aus:

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

Wenn Sie wirklich tun möchten, können Sie aber ein prototype verwenden müssen:

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 

(Beachten Sie, dass $_ dynamisch scoped ist, so was auch immer Wert, der es in dem Anrufer hat in der Funktion erhalten.)

List::Util und List::MoreUtils tun, um diese Art der Sache viel zu Funktionen erstellen, die Built-in aussehen und wirken wie Varianten von map/grep. Das ist wirklich der einzige Fall, in dem so etwas verwendet werden sollte.

+0

+1. Ich mag die Idee, $ _ mit der "for" -Anweisung zu lokalisieren - erlaubt 1-arg funcrefs, nett und prägnant zu sein. (Und ich nehme an, Sie könnten "local ($ a, $ b);" für 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

Warum haben Sie '&' auf der Vorderseite? –

+0

Vermutlich weil der OP einen hatte und die Antwort OPs Stil kopiert hat. Auch wenn das & Präfix wahrscheinlich nicht da sein sollte, wie Sinan Ünür erklärte. –

6

Erstens, verwenden Sie nicht & beim Aufruf sub s. Von perldoc perlsub:

Unterprogramme können rekursiv aufgerufen werden. Wenn ein Unterprogramm mit dem Formular & aufgerufen wird, ist die Argumentliste optional, und wenn sie weggelassen wird, wird kein Array @_ für das Unterprogramm eingerichtet: das Array @_ zum Zeitpunkt des Aufrufs ist stattdessen für das Unterprogramm sichtbar. Dies ist ein Effizienzmechanismus, den neue Benutzer möglicherweise vermeiden möchten.

Wenn Sie in der Lage Pass ein einfacher Block "sub something" sein wollen, müssen Sie einen Prototyp wie in verwenden:

sub something(&@); 

# later 

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

} 

Prototypes See.

Ich persönlich würde nur eine explizite Subref passieren:

something(sub { }); 
Verwandte Themen