Perl子类是否继承导入的模块和编译指示?

jljoyd4f  于 2022-11-15  发布在  Perl
关注(0)|答案(5)|浏览(140)

假设您在一个文件中有一个父Perl类:

#!/usr/bin/perl
package Foo;
use strict;
use warnings;

use Data::Dumper;

sub new{
    my $class = shift;
    my %self = ();
    return bless %self, $class;
}
1;

和不同文件中的子类:

#!/usr/bin/perl
package Bar;
use base "Foo";
1;

子类会继承父类的use语句吗?我知道new方法会被继承。
基本上,我正在尝试减少我的代码中的样板文件的数量,但我找不到这个问题的明确答案。

yvt65v4c

yvt65v4c1#

你在评论中问到Test::Most以及它如何减少样板文件。看看它的import方法。它将模块加载到它的命名空间中,将那些符号添加到@EXPORT中,然后通过goto重新调用另一个import,最终将它们放入调用命名空间中。Curtis在那里使用了一些非常厉害的黑魔法。虽然我想知道他为什么不使用 import_to_level 之类的命令。
我在Avoid accidently creating methods from module exportsThe Effective Perler中讨论了很多这类事情,这是在一个不同的背景下,但都是一些相同的问题。
这里有一个不同的例子。
如果其他模块加载了一个模块,你就可以访问它。但是依赖于它并不好。这里有三个独立的文件:

顶部.pm

use 5.010;

package Top;
use File::Spec;

sub announce { say "Hello from top!" }
1;

底部.pm

package Bottom;
use parent qw(Top);

sub catfiles { File::Spec->catfile( @_ ) }

1;

测试.pl

use 5.010;

use Bottom;

say Bottom->catfiles( qw(foo bar baz) );

say File::Spec->catfile( qw( one two three ) );

我只在 Top.pm 中加载File::Spec。然而,一旦加载,我就可以在Perl程序中的任何地方使用它。输出显示我可以在其他文件中“使用”该模块,即使我只在一个文件中加载了它:

Bottom/foo/bar/baz
one/two/three

要使这一点起作用,加载模块的代码部分必须在其他代码部分尝试使用该模块之前加载。正如我所说,依赖于这一点是一个坏主意:如果装载顺序改变或装载模块消失,则事情中断。
但是,如果你想导入符号,你必须在你想导入的包中显式地加载你想要的模块。这只是为了让导出模块定义那个包中的符号,而不是依赖于作用域。

dy2hfwbg

dy2hfwbg2#

啊,问得好!

Will the subclass inherit the use statements from the parent?

这取决于你所说的继承是什么意思。我不会在最后做任何假设,但答案是 * 也许 *。你看,perl混合了ClassesNamespaces的思想--package是一个可以描述它们中任何一个的术语。现在的问题是use语句,它所做的一切就是强制一个包包含,并将目标称为import()sub。这意味着它实质上对包以及类拥有无限的控制权。
现在,把perl中的所有方法与subs结合起来,按照惯例,subs$self作为第一个参数,剩下的就是perl 5了。这对那些知道如何使用它的人来说有着巨大的好处。虽然strict是一个词法编译指示,但Moose呢?

package BigMooseUser;
use Moose;

package BabyMooseUser;
our @ISA = 'BigMooseUser';

package Foo;
my $b = BabyMooseUser->new;
print $b->meta->name;

现在,BabyMooseUser从哪里得到构造函数(new)?它从哪里得到 meta类?所有这些都是从父类(命名空间)中的一个use Moose;提供的。

Will the subclass inherit the use statements from the parent?

在这里,在我们的例子中,如果 *use语句 * 的效果是添加方法,那么肯定。
这个主题比较深奥,这取决于你是在谈论编译指示,还是更模糊的对象框架,或者过程模块。如果你想在OO范式中减轻父命名空间对你自己命名空间的影响,请参阅namespace::autoclean

31moq8wy

31moq8wy3#

对于样板文件缩减,我有两个策略:我的大多数类都是Moose类,它负责OO设置,也给我提供了strict和warning。如果我想在很多包中都有可用的函数,我将创建一个项目特定的MyProject::Util模块,它使用Sub-Exporter来提供我自己的函数和接口。这使得它更加一致。如果我决定以后不管什么原因改变转储程序,我就不必改变很多代码。这还允许你对导出进行分组。一个类通常看起来像这样:

package Foo;
use Moose;
use MyProject::Util qw( :parsing :logging );

use namespace::autoclean;

# class implementation goes here

1;

如果有其他东西你认为是样板,并希望使简单的包括,这当然取决于这些东西是什么。

q8l4jmvw

q8l4jmvw4#

对您的问题的实用答案:要么使用,要么看看Modern::Perl是如何执行严格和警告的。

mlnl4t2r

mlnl4t2r5#

您可以通过检查每个包的符号表来获得明确的答案:
第一个

相关问题