将一个子程序传递给另一个子程序

时间:2013-04-09 23:23:32

标签: perl function functional-programming arguments

我有一个函数sub _where(\@ \&),它有两个参数:第一个是数组,第二个应该是另一个函数。这个其他函数返回一个布尔值,我想在sub _where(\@ \&)函数的for循环中调用它。

我无法将我传入的函数解压缩为自定义本地名称。我想我确实需要一些本地名称,因为应该可以将不同的布尔函数传递给我的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;
    }
}

应该传递的Function1:

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

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

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

应传递给where的函数2:

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

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

希望你们能在这里帮助我。干杯

6 个答案:

答案 0 :(得分: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);

答案 1 :(得分: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);

答案 2 :(得分: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);
    }
}

但不要混用这些方法。

答案 3 :(得分:1)

通过抓取第一个参数解决问题之后,以下是从代码引用中调用子例程的三种方法:

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

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

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

您可以通过阅读perlref手册页找到更多详细信息。

答案 4 :(得分: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;

答案 5 :(得分: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;