【问题标题】:Proper Perl OO Inheritance正确的 Perl OO 继承
【发布时间】:2018-02-03 23:21:57
【问题描述】:

我正在尝试为我们的代码库中的自定义模块创建一个子类。我们将模块放在一个目录中,该目录包含在所有文件中。所以我们从

use Env;
use lib "$ENV{OurKey}/RootLib"; # All of our modules are here

接下来,我有我的父模块,位于RootLib/Dir1/Parent.pm,它的代码已经存在很长时间了,所以我宁愿不改变任何一个,而是让孩子能够从它继承。

package Parent;
use strict;
use warnings;
use Env;
use lib "$ENV{OurKey}/RootLib";

sub new {
    my $proto = shift;
    my $class = ref($proto) || $proto;
    my $self = {};

    # Some other stuff

    bless ($self, $class);
    return $self;
}

在这一点上,我有点迷茫,因为我已经看到了许多不同的方法来定义子构造函数,但没有一个对我有用。这是我所拥有的,但它不起作用,因为在子包中找不到应该从父级继承的子例程。子包在RootLib/Dir1/Dir2/Child.pm

package Child;
use strict;
use warnings;
use vars qw(@ISA);
use Env;
use lib "$ENV{OurKey}/RootLib";

require Dir1::Parent;
push @ISA, 'Dir1::Parent';

sub new {
    # This constructor is clearly incorrect, please help
    my $proto = shift;
    my $class = ref($proto) || $proto;
    my $self = Parent::new($class);

    bless ($self, $class);
    return $self;
}

然后,在我的 test.pl 文件中,我有

use Env;
use lib "$ENV{OurKey}/RootLib";
use Dir1::Dir2::Child;

my $childObj = Child->new();
$childObj->inheritedParentSubroutine( ... ); # Cannot find this subroutine

【问题讨论】:

  • Env 这样使用是一个相当危险的模块;我建议仅将它与一组有限的包含一起使用:例如,use Env qw/ $PATH /;。此外,您不需要 需要use$ENV{OurKey} 的身份访问环境变量;原始 Perl 具有这种能力。
  • use Moose; 或相似者之一。
  • 注:1) use Env; 没用。 2)use lib "$ENV{OurKey}/RootLib"; 应该只位于脚本(.pl 文件)中,而不是模块(.pm 文件)中。
  • @el.pescado,Moose 不是一个选择。这将需要比使其正常工作所需的更多更改。 use Env、@ikegami 也是如此

标签: perl oop inheritance


【解决方案1】:

父类声明它在package Parent(即使包含它的文件是Dir1/Parent.pm),所以子类的@ISA应该只包含Parent

或者您可以使用一些额外的use lib ... 语句来解决您不幸的目录结构。

package Child;
use lib "$ENV{OurKey}/RootLib/Dir1";
require Parent;      # found in $OurKey/RootLib/Dir1/Parent.pm
our @ISA = ('Parent');
...

# test.pl
use lib "$ENV{OurKey}/RootLib/Dir1/Dir2";
use Child;           # found in $OurKey/RootLib/Dir1/Dir2/Child.pm
...

【讨论】:

  • 不幸的是,这行不通,因为(根据我之前做出的一些决定)Parent.pm 所在的目录与 Parent.pm 同名。所以我们有RootLib/Parent/Parent.pmRootLib/Parent/Dir2/Child.pm 我试过require Parent; 并没有找到它。
  • 那么如果你这样做use lib "RootLib/Parent"; require Parent;,它会失败吗?
  • 我看错了你的例子。似乎继承不喜欢通过目录搜索来找到父母和孩子。但是,我现在的问题是我收到了"Subroutine foo redefined at Parent.pm line xxx"。我怀疑这与我孩子的新子程序有关。
  • 在模块中包含 use lib 毫无意义。
【解决方案2】:

未来的父类有package Parent;,但你有@ISA = 'Dir1::Parent';。那些不匹配,这就是找不到该方法的原因。 (那个,事实上你实际上并没有在任何地方定义方法!)

文件名、package 语句中的名称、use 语句中的名称和@ISA 中的名称必须全部匹配。

以下是两种可能的解决方案。


如果类被命名为Dir1::ParentDir1::Dir2::Child

use lib "$ENV{OurKey}/RootLib";

use Dir1::Parent      qw( );
use Dir1::Dir2::Child qw( );

(请注意,use Env 已被删除,因为它没有被使用。)

(.../RootLib/)Dir1/Parent.pm:

package Dir1::Parent;          # Must match the file name.
use strict;
use warnings;

...

(.../RootLib/)Dir1/Dir2/Child.pm:

package Dir1::Dir2::Child;     # Must match the file name.
use strict;
use warnings;

use Dir1::Parent qw( );        # Must match the file name
our @ISA = 'Dir1::Parent';     #   and the package name.
   -or-
use parent 'Dir1::Parent';     # This can replace the other two lines.

...

如果类被命名为ParentChild

不要在模块中修改@INC(例如通过use lib)。您的脚本应包含以下内容:

use lib
   "$ENV{OurKey}/RootLib/Dir1",
   "$ENV{OurKey}/RootLib/Dir1/Dir2";

use Parent qw( );
use Child  qw( );

(请注意,在另一个库目录中包含一个库目录真的很奇怪!)

(.../RootLib/Dir1/)Parent.pm:

package Parent;                # Must match the file name.
use strict;
use warnings;

...

(.../RootLib/Dir1/Dir2/)Child.pm:

package Child;                 # Must match the file name.
use strict;
use warnings;

use Parent qw( );              # Must match the file name
our @ISA = 'Parent';           #    and the package name.
   -or-
use parent 'Parent';           # This can replace the other two lines.

...

至于构造函数,

家长:

sub new {
    my $class = shift;                # That proto thing is a bad practice.
    my $self = bless({}, $class);     # Don't need two lines to do this.

    # ...

    return $self;
}

孩子:

sub new {
    my $class = shift;                # That proto thing is a bad practice.
    my $self = $class::SUPER->new();  # Don't need two lines to do this.
                                      # If you don't need to do anything here,
    # ...                             #   you can just inherit the parent's new
                                      #   by removing this sub entirely.
    return $self;
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-07-13
    • 2016-11-05
    • 1970-01-01
    • 1970-01-01
    • 2023-03-18
    • 1970-01-01
    相关资源
    最近更新 更多