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

时间:2010-08-11 16:11:10

标签: perl

假设您在一个文件中有一个父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方法将被继承。

基本上我正在尝试减少代码中的样板量,但我找不到这个问题的明确答案。

5 个答案:

答案 0 :(得分:7)

您在评论中询问Test::Most以及它如何减少样板。看看它的import方法。它将模块加载到其命名空间中,将这些符号添加到@EXPORT,然后通过import重新调用另一个goto以最终将它们放入调用命名空间。这是Curtis在那里发生的一些严重的黑魔法,虽然我想知道他为什么不使用像 import_to_level 这样的东西。也许有一些我没想到的副作用。


我在Avoid accidently creating methods from module exportsThe Effective Perler中谈论了这类事情。它处于不同的背景下,但它是一些相同的问题。

这是一个不同的例子。

如果某个其他模块加载模块,您可以访问它。尽管如此依赖它并不好。以下是三个单独的文件:

<强> Top.pm

use 5.010;

package Top;
use File::Spec;

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

<强> Bottom.pm

package Bottom;
use parent qw(Top);

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

1;

<强> test.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

为此,在代码的任何其他部分尝试使用该模块之前,必须加载加载模块的代码部分。正如我所说,依赖于此是一个坏主意:如果加载顺序改变或加载模块消失,事情会中断。

但是,如果要导入符号,则必须在要导入的包中显式加载所需的模块。这就是导出模块定义该包中的符号。这不是取决于范围的东西。

答案 1 :(得分:4)

啊,好问题!

Will the subclass inherit the use statements from the parent? 

这取决于你继承的意思。直到最后我才会做出任何假设,但答案是也许。你知道,perl混合了ClassesNamespaces的想法 - package是一个可以描述其中任何一个的术语。现在问题是语句use它所做的只是强制包含,并调用目标import() sub。这意味着它基本上可以无限制地控制你的包裹 - 以及你的班级。

现在,将perl中的所有方法与subs结合起来,将$self作为第一个参数按惯例复制,并留下perl5。对于那些知道如何使用它的人来说,这有很大的好处。虽然严格是一个词汇编纂,那么Moose呢?

package BigMooseUser;
use Moose;

package BabyMooseUser;
our @ISA = 'BigMooseUser';

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

现在,BabyMooseUser从何处获取构造函数(new)?它从哪里获得元类?所有这些都是从父类(命名空间)中的单个use Moose;提供的。所以

Will the subclass inherit the use statements from the parent?

嗯,在这里,在我们的例子中,如果 use statement 的效果是添加方法,那肯定是。

这个主题有点深刻,这取决于你是在谈论编译指示,还是更加模糊的对象框架或程序模块。如果要在OO范例中减轻父级命名空间的影响,请参阅namespace::autoclean

答案 2 :(得分:4)

为了减少样板,我有几个策略:我的大多数类都是Moose类,它们负责OO设置并且还给我严格和警告。如果我想在许多包中提供函数,我将创建一个项目特定的MyProject::Util模块,它使用Sub-Exporter为我提供自己的函数和我自己的界面。这使它更加一致,如果我决定稍后因任何原因更改Dumper(例如),我不必更改大量代码。这也可以让你对出口进行分组。然后一个类通常看起来像这样:

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

use namespace::autoclean;

# class implementation goes here

1;

如果你认为其他东西是样板文件并希望简化包含,那么它当然取决于那些东西。

答案 3 :(得分:2)

对问题的务实回答:使用或查看Modern::Perl如何执行严格和警告。

答案 4 :(得分:1)

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

# examine-symbol-tables.pl
use Bar;

%parent_names = map{$_ => 1} keys %Foo::;
%child_names = map{$_ => 1} keys %Bar::;

delete $parent_names{$_} && ($common_names{$_} = delete $child_names{$_}) foreach keys %child_names;

print "Common names in symbol tables:\n";
print "@{[keys %common_names]}\n\n";

print "Unique names in Bar symbol table:\n";
print "@{[keys %child_names]}\n\n";

print "Unique names in Foo symbol table:\n";
print "@{[keys %parent_names]}\n\n";

$ perl inherit.pl
Common names in symbol tables:
BEGIN

Unique names in Bar symbol table:
ISA isa import

Unique names in Foo symbol table:
Dumper new VERSION