2013-04-09 136 views
1

我有一個函數sub _where(\@ \&),它有兩個參數:第一個是數組,第二個應該是另一個函數。這個其他函數返回一個布爾值,我想在我的函數sub _where(\@ \&)函數循環中調用它。將一個子程序傳遞給另一個子程序

我無法解壓我傳入的自定義本地名稱的函數。我想我確實需要一些本地名稱,因爲它應該可以將不同的布爾函數傳遞給我的where函數。

其中:

sub _where(\@ \&) 
{ 
    my @stud = @{$_[0]}; 
    my $student; 
    my $function = shift; 
    my $bool = 0; 
    my $i; 

    for $i(0..$#stud) 
    { 
     my $student = $stud[$i]; 
     function $student; 
    } 
} 

功能1應該傳遞:

sub name_starts_with($) 
{ 
    my $letter = 'B'; 
    my $student = shift; 
    my $first; 

    $first = substr($student -> name, 0, 1); 

    if($first eq $letter) 
    { 
     return 1; 
    } 
} 

功能2應該傳遞給where

sub points_greater_than($) 
{ 
    my $sum_pts = 5; 
    my $student = shift; 
    my $pts; 

    $pts = $student -> points; 
    if($pts > $sum_pts) 
    { 
     return 1; 
    } 
} 

希望你們能幫助我在這裏。乾杯

+0

,能得到任何錯誤訊息? – 2013-04-10 00:29:31

回答

1

你在函數_where中有參數處理中的錯誤。您正在將數組引用放入$function變量中。你所要做的

my @stud = @{shift()}; 
my $student; 
my $function = shift(); 

my @stud = @{$_[0]}; 
my $student; 
my $function = $_[1]; 

或者我寧願

sub _where(\@ \&) 
{ 
    my ($stud, $function) = @_; 

    for my $student (@$stud) 
    { 
     $function->($student); 
    } 
} 

只是不要混用這些方法。

+0

您可以成功混合使用這兩種方法,但這是一種很少用的高級技術。例子:允許一個子程序用作'Module :: func()'和'Module-> func()''package; sub func {shift if if $ _ [0] eq __PACKAGE__; ...}' – 2013-04-11 04:43:53

+1

是的,你可以但*不*是很好的建議。我沒有寫過你不能。 Perl允許你做很多瘋狂的事情,但你不應該做很多這樣的事情。 – 2013-04-11 05:23:21

+0

@希內克-Pichi-Vychodil:我是不是在暗示那些事情和問題的原因。實際上OP的代碼不起作用的主要原因是'$ student'不是'function $ student'中的一個幸運對象或包名。 – Borodin 2013-04-11 11:08:11

2

的一個問題是你如何得到參數:

my @stud = @{$_[0]}; # <-- this doesn't remove first parameter from list 
my $student; 
my $function = shift; # <-- therefore you'll still get first parameter, not second 

試試這個修復:

my $function = $_[1]; # always get second parameter 

更新

添加例如如何通過參考運作到其他功能:

_where(\@stud, \&name_starts_with); 
1

在修復與抓的第一個參數的問題,這裏有三種方法可以從代碼引用調用一個子程序:

&$function($student); # uses the fewest characters! 

&{$function}($student); # the style you're using for the array ref 

$function->($student); # my favorite style 

你可以找到很多更詳細的信息,通過閱讀perlref手冊頁。

3

你不應該使用原型。他們在Perl中與其他語言的工作方式不同,幾乎從不是一個好的選擇。

除非要在不影響外部數據的情況下對其進行修改,否則還應避免製作傳入陣列的本地副本。

最後,以下劃線開頭的子程序名通常表示它是一個類的私有方法。這裏看起來不是這種情況。

你的代碼看起來應該是這樣

sub _where { 

    my ($stud, $function) = @_; 
    my $student; 
    my $bool = 0; 

    for my $i (0..$#stud) { 
     my $student = $stud->[$i]; 
     $function->($student); 
    } 
} 

然後,你可以把它作爲

_where(\@student, \&function); 
+0

您應該在您的子程序需要代碼引用時使用原型。 – mob 2013-04-10 00:41:44

+3

@mob不,你不應該。當你的子程序需要BLOCK時,你應該(實際上)使用原型。在OP的例子中,沒有必要使用具有常規代碼引用的原型。 – 2013-04-10 03:44:04

+0

你爲什麼不演示如何將它改爲['foreach'](http://perldoc.perl.org/perlsyn.html#Foreach-Loops)循環? – 2013-04-11 04:46:50

1

你似乎在試圖寫在Perl另一種語言。伊克。試試這個:

sub _where 
{ 
    my $students = shift; 
    my $function = shift; 
    $function->($_) for @$students; 
} 

sub name_starts_with 
{ 
    my $student = shift; 
    my $letter = 'B'; 
    my $first = substr($student->name, 0, 1); 
    return $first eq $letter; # same as 'return $first eq $letter ? 1 : undef;' 
} 

sub points_greater_than 
{ 
    my $student = shift; 
    my $sum_pts = 5; 
    my $pts  = $student->points; 
    return $pts > $sum_pts; 
} 

而你也這樣稱呼它_where(\@students, \&name_starts_with)

但我不正是你_where功能的目的是,因爲它不返回任何東西(除了評估的最後聲明,這似乎並沒有在這方面太有用)。

也許你只是想grep的?

my @students_b = grep { substr($_->name, 0, 1) eq 'B' } @students;

1

如果更改了參數的順序,使CODEREF首先,你的代碼會多一點點Perlish的。

sub _where(\&@){ 
    my $func = shift; 
    my @return; 

    for(@_){ 
    push @return, $_ if $func->($_); 
    } 

    return @return; 
} 

如果你在Perl樣樣精通,你會發現,我只是重新實現grep(很差)。

sub name_starts_with{ 
    'B' eq substr($_->name, 0, 1); 
} 

sub points_greater_than{ 
    $_->points > 5; 
} 

my @b_students = _where(&name_starts_with, @students); 

my $count_of_students_above_5 = _where(&points_greater_than, @students); 

由於這些子程序現在依靠$_,我們應該只使用grep

my @b_students = grep(&name_starts_with, @students); 

my $count_of_students_above_5 = grep(&points_greater_than, @students); 

由於那些子程序也很短,所以只使用一個塊。

my @b_students = grep { 
    'B' eq substr($_->name, 0, 1) 
} @students; 

my $count_of_students_above_5 = grep { 
    $_->points > 5; 
} @students; 
相關問題