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

问题描述 投票:5回答:4

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

这里是代码。

  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;

期望[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

我在这里做错了什么?

perl6 function-object
4个回答
5
投票

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

但是,如果您实际上没有在这些方法中使用对象做某些事情,为什么还要使用method?那么,它们也可能是sub,您can作为参数传递。

也许这是最好的例子:

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]

仅返回一个恒定值(在这种情况下为sub filter)的第一个True,在带有空主体的签名中更容易表示。

filter_lt_10filter_gt_10子仅需要取反的条件,因此使用not

get_filtered_list方法应该是私有的,因此请在前缀!之前将其设为私有方法。

get_filtered_list_lt_10中,您现在需要使用get_filtered_list而不是!来调用.。然后,通过在filter_lt_10前面添加&子作为参数(否则,它将被认为是对没有任何参数的子的调用,否则将失败)。

更改get_filtered_list以使用内置的grep方法:这需要一个Callable块,该块具有单个参数,并且应该返回True来包含其所处理列表的值。由于sub带有单个参数is Callable,因此我们可以直接在其中指定子项。

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

[一些一般的编程说明:对我来说,潜艇的命名令人困惑:对我来说,它们应该分别命名为filter_le_10filter_ge_10,因为它们确实是在我看来。另外,如果您确实不想进行任何临时过滤,而只希望从一组特定的预定义过滤器中进行过滤,则最好使用常量或enum创建一个分配表,并使用该表来指示您想要的过滤器,而不是使用其他要制作和维护的方法的名称来编码此信息。

希望这会有所帮助。


3
投票

TL; DR您告诉P6在调用filter方法时需要哪些参数。这样,您在调用约定的参数时就无法通过。因此,P6代表您投诉。要解决该问题,请传递您告诉P6期望的参数,或者停止告诉P6期望它们。 :)


消息说期望的2,得到的是1,而不是期望的1得到的0

这是因为self被隐式传递并添加到消息详细信息的此附加位的“预期”和“获得”总数中,两者都增加了一个。 (此细节可能不及Awesome少,即我们可能应考虑解决的问题。)


当我run your code on tio时得到:

Too few positionals passed; expected 2 arguments but got 1
  in method filter at .code.tio line 27
  in method print_filtered_list at .code.tio line 12
  in block <unit> at .code.tio line 42

第27行的方法[[declaration method filter($l) {...}告诉P6为每个.filter方法call期望two自变量:

  • 煽动者。 (这将绑定到self。)我们将其称为

    argument A。

    ]
  • 位置参数。 (这将绑定到$l参数)。我们称它为[[参数B

但是在第12行的&{self.filter}中,当您为.filter方法call

提供一个

argument A,即一个激进的参数时,您没有提供argument B ,即位置参数(after filter,例如&{self.filter(42)})。

因此Too few positionals passed; expected 2 arguments but got 1

2
投票
3 class list_filter { 4 has @.my_list = (1..20); 5 6 # will be overriding this in derived classes 7 method filter1($l) { return True; } 8 method filter2($l) { return True; } 9 10 # same print method I will be calling from all derived class objects 11 method print_filtered_list($type) { 12 my @outlist = self.get_filtered_list($type); 13 say @outlist; 14 } 15 16 # private 17 method get_filtered_list($type) { 18 my @newlist = (); 19 for @.my_list -> $l { 20 my $f = "filter$type"; 21 if (self."$f"($l)) { push(@newlist, $l); } 22 } 23 return @newlist; 24 } 25 } 26 27 class list_filter_lt_10 is list_filter { 28 method filter1($l) { 29 if ($l > 10) { return False; } 30 return True; 31 } 32 method filter2($l) { 33 if ($l > 10) { return False; } 34 if ($l < 5) { return False; } 35 return True; 36 } 37 } 38 39 class list_filter_gt_10 is list_filter { 40 method filter1($l) { 41 if ($l < 10) { return False; } 42 return True; 43 } 44 method filter2($l) { 45 if ($l < 10) { return False; } 46 if ($l > 15) { return False; } 47 return True; 48 } 49 } 50 51 my $listobj1 = list_filter_lt_10.new(); 52 $listobj1.print_filtered_list(1); 53 $listobj1.print_filtered_list(2); 54 55 my $listobj2 = list_filter_gt_10.new(); 56 $listobj2.print_filtered_list(1); 57 $listobj2.print_filtered_list(2); 58

输出:

./b.pl6
[1 2 3 4 5 6 7 8 9 10]
[5 6 7 8 9 10]
[10 11 12 13 14 15 16 17 18 19 20]
[10 11 12 13 14 15]

0
投票
[要获取方法,请使用运行obj.^lookup(method name),并通过传入对象本身(通常为“ self”)作为第一个参数,然后传入其他参数来调用它。要将对象绑定到该函数,以便不必每次都显式添加该对象,请使用assuming函数。

class MyClass { method log(Str $message) { say now ~ " $message"; } method get-logger() { return self.^lookup('log').assuming(self); } } my &log = MyClass.get-logger(); log('hello'); # output: Instant:1515047449.201730 hello

© www.soinside.com 2019 - 2024. All rights reserved.