2013-04-09 91 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; 
相关问题