假设您在一个文件中有一个父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方法将被继承。
基本上我正在尝试减少代码中的样板量,但我找不到这个问题的明确答案。
答案 0 :(得分:7)
您在评论中询问Test::Most以及它如何减少样板。看看它的import
方法。它将模块加载到其命名空间中,将这些符号添加到@EXPORT
,然后通过import
重新调用另一个goto
以最终将它们放入调用命名空间。这是Curtis在那里发生的一些严重的黑魔法,虽然我想知道他为什么不使用像 import_to_level 这样的东西。也许有一些我没想到的副作用。
我在Avoid accidently creating methods from module exports的The 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混合了Classes
和Namespaces
的想法 - 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