如何在perl 6中将类方法作为参数传递给该类的另一个方法

Bha*_*arS 5 function-object perl6

我有一个如下的脚本。目的是采用不同的过滤方法来过滤列表。

这是代码。

  2 
  3 class list_filter {
  4   has @.my_list = (1..20);
  5 
  6   method filter($l) { return True; }
  7 
  8   # filter method
  9   method filter_lt_10($l) {
 10     if ($l > 10) { return False; }
 11     return True;
 12   }
 13 
 14   # filter method
 15   method filter_gt_10($l) {
 16     if ($l < 10) { return False; }
 17     return True;
 18   }
 19 
 20   # expecting a list of (1..10) to be the output here
 21   method get_filtered_list_lt_10() {
 22     return self.get_filtered_list(&{self.filter_lt_10});
 23   }
 24 
 25   # private
 26   method get_filtered_list(&filter_method) {
 27     my @newlist = ();
 28     for @.my_list -> $l {
 29       if (&filter_method($l)) { push(@newlist, $l); }
 30     }
 31     return @newlist;
 32   }
 33 }
 34 
 35 my $listobj = list_filter.new();
 36 
 37 my @outlist = $listobj.get_filtered_list_lt_10();
 38 say @outlist;
Run Code Online (Sandbox Code Playgroud)

期望[1..10]是这里的输出。但是出现以下错误。

Too few positionals passed; expected 2 arguments but got 1

  in method filter_lt_10 at ./b.pl6 line 9
  in method get_filtered_list_lt_10 at ./b.pl6 line 22
  in block <unit> at ./b.pl6 line 37
Run Code Online (Sandbox Code Playgroud)

我在这里做错了什么?

Eli*_*sen 5

在Perl 6中将方法作为参数传递,要么要求您使用MOP(元对象协议)方法,要么按名称传递方法(然后将在运行时为您进行查找)。

但是,method如果您没有真正使用这些方法对对象做某事,为什么还要使用s?那么它们也可能是subs,您可以将其作为参数传递。

也许这是最好的例子:

class list_filter {
    has @.my_list = 1..20;  # don't need parentheses

    sub filter($ --> True) { } # don't need code, signature is enough

    # filter sub
    sub filter_lt_10($l) { not $l > 10 }

    # filter sub
    sub filter_gt_10($l) { not $l < 10 }

    # private
    method !get_filtered_list(&filter_sub) {
        @.my_list.grep(&filter_sub);
    }

    # expecting a list of (1..10) to be the output here
    method get_filtered_list_lt_10() {
        self!get_filtered_list(&filter_lt_10);
    }
}

my $listobj = list_filter.new();
my @outlist = $listobj.get_filtered_list_lt_10();
say @outlist; # [1 2 3 4 5 6 7 8 9 10]
Run Code Online (Sandbox Code Playgroud)

第一个sub filter仅返回一个常数(在这种情况下为True),可以很容易地在带有空主体的签名中表示。

filter_lt_10filter_gt_10潜艇只需要否定的条件,因此使用的not

get_filtered_list方法应该是私有方法,因此请在前缀之前使其成为私有方法!

在中,get_filtered_list_lt_10您现在需要get_filtered_list!而不是调用.。然后,您可以通过在filter_lt_10前缀之前将sub作为参数传递&(否则,它将被视为对不带任何参数的sub的调用,否则将失败)。

更改get_filtered_list为使用内置grep方法:这需要一个Callable采用单个参数的块,并且该块应返回一些内容True以包含其所使用的列表的值。由于sub采取一个参数一个Callable,我们就可以有直接指定子。

希望这有道理。我试图尽可能地接近预期的语义。

一些一般的编程说明:在我看来,sub的命名是令人困惑的:在我看来,应将其命名为filter_le_10and filter_ge_10,因为这确实是它们在我看来。另外,如果您确实不想进行任何临时过滤,而只希望从一组特定的预定义过滤器中进行过滤,则最好使用常量或enums 创建一个调度表,并使用该表来指示您要使用哪个过滤器而不是使用另一种制造和维护方法的名称来编码此信息。

希望这可以帮助。