1

我有一个带有sub _where(\@ \&)2 个参数的函数:第一个是数组,第二个应该是另一个函数。这个另一个函数返回一个布尔值,我想在我的 forsub _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;
    }
}

应该传递的 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;
    }
}

应传递给的 Function2 where

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

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

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

4

6 回答 6

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);
于 2013-04-10T00:32:50.650 回答
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);
于 2013-04-09T23:28:13.880 回答
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;
于 2013-04-11T04:35:53.020 回答
1

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

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

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

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

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

于 2013-04-10T00:08:58.930 回答
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;

于 2013-04-10T03:59:44.090 回答
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);
    }
}

但不要混合使用这些方法。

于 2013-04-09T23:29:11.050 回答