可以将方法视为常规子例程吗?

Can methods be treated as regular subroutines?

是否可以将方法分配给变量并将它们作为参数在 class 中传递,类似于子例程?

我知道它们可以通过其他方法中的 self.self!(或任何命名的显式调用者)访问,但我想知道是否可以将方法的代码对象传递为另一个方法的参数。

您是否考虑过传递方法名称?

class Foo {
    method bar($a) { dd $a }
}
my $name = "bar";
Foo."$name"(42);  # 42

语法需要字符串化 括号来指示您要调用该方法。如果你真的想使用 Method 对象并传递它,你可以,但是没有真正好的语法:

class Foo {
    method bar($a) { dd $a }
}
constant &B = Foo.^find_method("bar");
B(Foo, 42)  # 42

在这个例子中,常量&B是在编译时创建的。但您也可以在运行时调用此方法,例如当方法名在变量中时:

my $name = "bar";
my $method = Foo.^find_method($name);
$method(Foo, 42);

但是,在那种情况下,您可能最好使用 ."$name"() 语法。有关详细信息,请参阅 https://docs.raku.org/routine/find_method

有两种通用机制可以将方法作为 first class citizen (something that can be passed around as an argument), depending on whether a method is has 作用域(几乎所有方法都是)或 my 作用域。

.^find_method... 找到一个 has 作用域方法

绝大多数方法都保存在 classes 中,并且在没有显式范围声明符的情况下声明。这些都是(隐含地)has 范围内包含它们的 class。

要将 has 作用域方法作为参数传递,您需要 找到 它。 find 操作必须相对于包含该方法或从包含该方法的 class 继承的某些 class 启动。即使您知道该方法就在您启动 find 操作的 class 中,也是如此。共有三个选项:

  • .^find_method, as noted by ugexe++, is the usual tool. As you might expect, it searches inherited classes in Method Resolution Order,从 .^find_method 调用者的 class 开始。

  • 在极少数情况下,您可能希望使用 .^find_method_qualified。这会在 MRO 的更高层开始搜索,高于调用者的 class.

  • 为了完整起见,我将包括另一种方法:.^lookup。但请阅读文档中的警告。你几乎肯定不应该使用这个方法,特别是如果你想做的是调用这个方法。请改用 .^find_method... 方法之一。

所以:

.has-way given class {
  method has-way { my $m = self.^find_method: 'm'; self.m-as-arg: $m }
  method m-as-arg ($m) { say self.$m } # has way
  method m { 'has way' }
}

&foo 引用 my 作用域方法

一些方法没有 has 作用域,而是用 my.

声明

对于这些 lexical 方法,将它们作为参数传递的机制是简单地使用前缀 & 标记来引用它们,就像您为 subs.

所以:

.my-way given class {
  method my-way { self.m-as-arg: &m }
  method m-as-arg ($m) { say self.$m }     # my way
  my method m { 'my way' }
}