提问者:小点点

使用模块加载一组相关功能


我想用Raku Modules对一些函数进行分组,我经常使用。因为这些函数都是松耦合的,我不喜欢在一个类中添加它们。

我喜欢use的想法,您可以在其中选择应该导入哪些函数,但我不喜欢导入的函数然后存储在全局命名空间中。

例如,如果我有一个文件my_util. pm6

#content of my_util.pm6
unit module my_util;
our sub greet($who) is export(:greet) {
    say $who;
}
sub greet2($who) is export(:greet2) {
    say $who;
}
sub greet3($who) is export(:greet3) {
    say $who;
}

和一个文件test. p6

#!/usr/bin/perl6
#content of test.p6
use v6.c;
use lib '.';
use my_util :greet2;

greet("Bob");    #should not work (because no namespace given) and also doesn't work
greet2("Bob");   #should not work (because no namespace given) but actually works
greet3("Bob");   #should not work (because no namespace given) and also doesn't work
my_util::greet("Alice");     #works, but should not work (because it is not imported)
my_util::greet2("Alice");    #should work, but doesn't work
my_util::greet3("Alice");    #should not work (because it is not imported) and also doesn't work

我想通过调用所有函数my_util::greet()而不是通过greet()。

my_util. pm6中定义的函数greet()非常接近我的要求,但是因为它被定义为我们的,所以它总是被导入。我喜欢的是这种可能性,选择应该导入哪些函数,并且应该可以将其保留在模块定义的命名空间中(即它不污染全局命名空间)

有谁知道,我如何才能做到这一点?


共1个答案

匿名用户

词法作用域和包符号表是不同的东西。

>

  • my将符号添加到当前词法范围。

    our将符号添加到当前词法范围和当前包的公共符号表中。

    use将请求的符号复制到当前词法范围内。
    这称为“导入”。

    ::分隔符执行包查找-即foo::greet在包foo的公共符号表中查找符号greet
    这不涉及任何“导入”。

    包的公共符号表是相同的,无论从哪里引用…没有机制使其中的单个符号从不同范围可见。

    你可以让冒号成为子程序实际名称的一部分…

    sub foo::greet($who) is export(:greet) { say "Hello, $who!" }
    # This subroutine is now literally called "foo::greet".
    

    …但是你不能再以正常的方式调用它了(因为解析器会将其解释为上面的规则4),所以你必须使用笨重的“间接词法查找”语法,这显然不是你想要的:

    foo::greet "Sam";          # Could not find symbol '&greet'
    ::<&foo::greet>( "Sam" );  # Hello, Sam!
    

    所以,你最好的选择是…

    • 使用我们的声明子例程,并接受这样一个事实,即所有子例程都可以从使用模块的所有范围访问。
      或者:
    • 将公共前缀直接添加到子例程名称中,但使用没有问题的分隔符(例如破折号),然后正常导入它们:
    unit module foo;
    sub foo-greet($who)  is export(:greet)  { ... }
    sub foo-greet2($who) is export(:greet2) { ... }
    sub foo-greet3($who) is export(:greet3) { ... }