2009-08-21 14 views
2

マップ関数のようなものを受け入れる関数を書くにはどうすればよいですか?Perlサブ関数に関数を渡すにはどうすればよいですか?

例:

$func = sub { print $_[0], "hi\n" }; 
&something($f); 
sub something 
{ 
    my $func = shift; 
    for ($i = 0; $i < 5; $i++) 
    { $func->($i); } 
} 
正常に動作します

が、その後、私は

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

それ文句を言わない仕事をしたし、funcが未定義の参照であると言います。

私の質問は、どのように私はperlsマップ関数のようなパラメータを受け入れる関数を書くだろうか?

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

答えて

17

map機能は非常に不思議な構文を持っており、あなたはおそらく、あなたが本当に正当な理由がない限り、それをコピーする必要はありません。あなたが本当にこれをしたい場合は、しかし、あなたはprototypeを使用する必要が

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

:ちょうどこのような定期的な匿名のサブを使用

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 

$_はそう、動的にスコープされていることに注意してくださいどのような値は、呼び出し元に関数内に保存されている。)

List::UtilList::MoreUtilsビルトインを見て関数を作成し、の変種のように行動するためにこの種のものをたくさんやります10/grep。これは本当にこのようなものが使われるべき唯一のケースです。

+0

+1。私は$ _を "for"ステートメントでローカライズするというアイデアが好きです.1つの引数のファンクションを素敵で簡潔にすることができます。 (そして、私はあなたが "local($ a、$ b);" 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

なぜあなたは前に '&'持っています:

私は個人的にはちょうど明白なSUBREFを渡すでしょうか? –

+0

おそらくOPが1つあり、その答えはOPのスタイルをコピーしていたためです。 SinanÜnürが説明したように、&接頭辞はおそらくそこにあるべきではありません。 –

6

まず、subを呼び出すときは&を使用しないでください。 perldoc perlsub

サブルーチンは再帰的に呼び出すことができます。サブルーチンが&フォームを使用して呼び出された場合、引数リストはオプションです。省略すると、@_配列はサブルーチン用に設定されません。呼び出し時の@_配列がサブルーチンに表示されます。これは、新規ユーザーが回避したいと考える効率的な仕組みです。

あなたはプレーンなブロックに「sub something」できるパスにしたい場合は、あなたがのようにプロトタイプを使用する必要があります。

sub something(&@); 

# later 

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

} 

Prototypesを参照してください。

something(sub { }); 
関連する問題