如何通过一个类的方法作为参数传递给类的另一种方法在Perl 6(how to pass a clas

2019-09-30 18:34发布

我有一个像下面的脚本。 目的是使不同的过滤器的方法来筛选列表。

下面是代码。

  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

我在做什么错在这里?

Answer 1:

在Perl 6任一传递的方法作为一个参数要求使用MOP(元对象协议)的方法,或通过按名称的方法(其然后会做的查找为在运行时)。

但是,为什么使用method ■如果你没有真正做一些与这些方法的对象? 他们很可能会成为sub当时的,它可以作为参数传递。

也许,这就是最好的例子:

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取一个参数 Callable ,我们就可以有直接指定子。

希望这是有意义的。 我试图保持尽可能接近到预期的语义。

一些通用的编程备注:感觉对我来说,潜艇的命名是混乱:感觉对我来说,他们应该被称为filter_le_10filter_ge_10 ,因为这是真的,他们做什么,在我看来。 此外,如果你真的不想要任何的ad-hoc过滤,而是从一组特定的预定义过滤器的过滤只,你很可能会通过创建一个使用常数或调度表更好enum S,并用它来指示哪个过滤器你想要的,而不是编码另一种方法来制作,维护的名称信息。

希望这可以帮助。



Answer 2:

TL; DR你告诉P6呼唤你的时候会发生什么参数filter方法。 然后你未能通过商定的参数(S),当你打电话吧。 所以P6抱怨代为通知。 为了解决这个问题,可以传递参数()你告诉P6期待或停止告诉P6指望他们。 :)


有消息称预计2 ,拿到了1 ,而不是预期的1得到0

这是因为self被隐,并加入到了“预期”和“得到”总计在消息细节这一附加位,由一个碰撞均上涨。 (这个细节可能比真棒少,即是我们或许应该考虑固定。)


当我在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

该方法声明 method filter($l) {...}在第27行告诉P6期待每个有两个参数.filter方法调用

  • 在调用者。 (这将被绑定到self 。)让我们把那个理着

  • 位置参数。 (这将被绑定到$l参数)。 让我们把这样的说法B中

但在&{self.filter}管线12,而你提供.filter与一个参数的方法的呼叫 ,即,调用者参数,您没有提供一个参数B,即一个位置参数( filter ,例如&{self.filter(42)} )。

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



Answer 3:

找到了。 这是为我工作。

  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]


Answer 4:

&{self.method}语法是新的我,所以感谢。 不幸的是,如果需要的参数不工作。 您可以使用sub如提到的其他海报,但如果你需要使用的方法,你可以通过调用获取方法self.^lookup ,它是利用伊丽莎白提到的元对象协议。 (“^”是指你不打电话就是这样类的一部分,而是其中包含主类的胆量/实施细则“影子”类的一部分的方法。)

为了得到一个方法,用跑obj.^lookup(method name) ,并通过在对象本身传递(经常“自我”)作为第一个参数,那么其他的参数调用它。 要将对象绑定到功能,所以它不需要每次都明确添加,使用假设功能。

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


文章来源: how to pass a class method as argument to another method of the class in perl 6