出于工作目的,我正在将一个框架从 Perl5 重写为 Perl6。在某个地方,我需要通过执行 public sub
从其他模块/类收集信息。他们可能会提供;或者他们可能不会。所以,有必要找出sub
是否存在。当直接引用模块( Foo::<&my-sub>
)或通过字符串中的符号名称(&::("Foo")::my-sub)引用模块时,这并不是什么大问题。但为了简单起见,我想允许按原样传递模块名称(假设 collector
是收集信息的方法):
self.collector( Foo );
哪里Foo
可能是以下内容:
module Foo {
use Bar;
use Baz;
our sub my-sub { Bar, 'Baz' }
}
这就是我遗漏了 Perl6 语法中一些重要内容的地方,因为:
method collector ( $mod ) {
my $mod-name = $mod.WHO;
my @mods;
with &::($mod-name)::my-sub {
@mods.push: &$_();
}
}
这是目前我执行任务的唯一方法。
不过我还没有尝试类型捕获。我想应该会按预期工作。所以,问题更多的是扩展我的语法知识。
最佳答案
最终的解决方案来自于Vadim在问题评论中的交流。这可以说是疯狂的。他们认为这很美丽。我该跟谁争论呢? .oO(哈哈,呵呵,嘻嘻……)
my $pkg-arg = (Int, 'Int').pick;
my \pkg-sym = $pkg-arg && ::($pkg-arg);
my \sub-ref = &pkg-sym::($subname);
有两种明显有用的方法来引用包:
它的符号名称。
Int
是 Int 类的符号名称。它的字符串名称。
'Int'
是 Int 类的字符串名称。
Vadim 很合理地希望找到一个能够同时解决这两个问题的解决方案。
在此答案的解决方案中,我通过随机选择一种参数并将其分配给 $pkg-arg
来模拟两种类型的参数:
my $pkg-arg = (Int, 'Int').pick;
现在我们需要正常化。如果我们有了一个象征性的名字,我们就可以开始了。但如果它是字符串名称,我们需要将其转换为符号名称。
Vadim 在其问题的评论中展示了几种实现此目的的方法。该解决方案使用第三个选项:
my \pkg-sym = $pkg-arg && ::($pkg-arg);
如果$pkg-arg
是一个符号名称,那么它将是False
。对于 False
LHS,&&
会短路并返回其 LHS。如果 $pkg-arg
是字符串名称,则 &&
将返回其 RHS,即 ::($pkg-arg)
这是使用 $pkg-arg
作为字符串名称的符号查找。
结果是 pkg-sym
最终包含一个包符号名称(如果查找未能找到匹配的符号名称,则返回 Failure
)。
剩下最后一行。它会在包 pkg-sym
中查找名为 $subname
的子包:
my \sub-ref = &pkg-sym::($subname);
需要 &
以确保将 RHS 视为引用而不是尝试调用例程。并且 pkg-sym
必须是无符号标识符,否则代码将无法工作。
在这三行代码的末尾sub-ref
包含Failure
或对所需子的引用。
关于syntax - 内省(introspection)模块/类/等的替代语法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51957518/