2009-08-21 124 views
2

我該如何編寫一個接受類似map函數的函數呢?如何將函數傳遞給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函數?

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

回答

17

map功能具有非常神奇的語法,你可能不希望除非你有一個很好的理由將它複製;只是使用普通的無名子,是這樣的:

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

如果你真的想這樣做,不過,你需要使用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 

(注意:$_動態範圍的,所以任何值已在來電者的功能被保留。)

List::UtilList::MoreUtils做這樣的事情很多創建外觀內置功能和行爲像的變種10/grep。這真的是唯一的情況下應該使用這樣的東西。

+0

+1。我喜歡用「for」語句對$ _進行本地化的想法 - 允許1-arg funcrefs變得簡潔明瞭。 (我想你可以「本地($ a,$ b);」對於2-arg funcrefs la sort()。) – 2009-08-22 18:06:59

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

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

爲什麼你有'&'放在前面? – 2009-08-21 16:58:28

+0

大概是因爲OP有一個,答案是複製OP的風格。即使前綴可能不應該在那裏,正如SinanÜnür解釋的那樣。 – 2009-08-21 17:22:37

6

首先,在撥打sub s時不要使用&。從perldoc perlsub

子程序可以遞歸調用。如果使用&表單調用子例程,則參數列表是可選的,如果省略,則不會爲該子例程設置@_數組:調用時該數組的@_對子例程可見。這是新用戶可能希望避免的效率機制。

如果你希望能夠通過一個簡單的塊「sub something」,您需要使用的原型爲:

sub something(&@); 

# later 

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

} 

Prototypes

我個人只想傳遞一個明確的子參考:

something(sub { });