可以将方法视为常规子例程吗?
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 方法,将它们作为参数传递的机制是简单地使用前缀 &
标记来引用它们,就像您为 sub
s.
所以:
.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' }
}
是否可以将方法分配给变量并将它们作为参数在 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 方法,将它们作为参数传递的机制是简单地使用前缀 &
标记来引用它们,就像您为 sub
s.
所以:
.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' }
}