【问题标题】:Replacing a class in Perl ("overriding"/"extending" a class with same name)?替换 Perl 中的类(“覆盖”/“扩展”同名的类)?
【发布时间】:2014-07-13 19:22:37
【问题描述】:

我正在尝试Iterate directories in Perl, getting introspectable objects as result,主要是这样当我在来自IO::All 的返回中使用Dumper 时,我可以打印mtime 之类的字段。

我发现,它可以做到,如果在模块IO::All::File(对我来说,/usr/local/share/perl/5.10.1/IO/All/File.pm),我添加行field mtimef => undef;,然后修改它的sub file,让它运行$self->mtimef($self->mtime); (注意,此字段不能与相应的方法/属性具有相同的名称 (mtime),因为它们是在 IO::All 中动态分配的)。所以,从本质上讲,我对“重载”不感兴趣,因为多个函数签名具有相同的名称 - 我想用它的扩展版本“替换”或“覆盖”一个类(不知道这是怎么回事正确称呼),但名称相同;所以所有其他可能使用它的类,从那时起继续使用扩展版本。

现在对我来说最好的方法是,如果我能以某种方式从我实际的“可运行”Perl 脚本中“替换”IO::All::File 类——如果可能的话,通过使用继承机制,这样我就可以添加什么是“额外的”。为了说明我的意思,这里有一个例子:

use warnings;
use strict;

use Data::Dumper;
my @targetDirsToScan = ("./");

use IO::All -utf8 ;                          # Turn on utf8 for all io

# try to "replace" the IO::All::File class

{ # recursive inheritance!
  package IO::All::File;
  use IO::All::File -base;

  # hacks work if directly in /usr/local/share/perl/5.10.1/IO/All/File.pm

  field mtimef => undef; # hack

  sub file {
    my $self = shift;
    bless $self, __PACKAGE__;
    $self->name(shift) if @_;
    $self->mtimef($self->mtime); # hack
    return $self->_init;
  }

  1;
}

# main script start

my $io = io(@targetDirsToScan);
my @contents = $io->all(0);                    # Get all contents of dir
for my $contentry ( @contents ) {
  print Dumper \%{*$contentry};
}

...失败并显示“在 /usr/local/share/perl/5.10.1/IO/All/Base.pm 第 13 行的包 'IO::All::Filesys' 中检测到递归继承。”;如果您注释掉“递归继承”部分,则一切正常。

我很清楚为什么这种语法会发生这种情况 - 但是,是否有一种语法或方法可以用来“替换”一个具有相同名称的扩展版本的类,类似于我上面的尝试方式?显然,我想要相同的名称,这样我就不必更改 IO::All(或包中的任何其他文件)中的任何内容。另外,我最好在“runner”Perl 脚本中执行此操作(这样我就可以将所有内容都放在一个脚本文件中,并且我不必维护多个文件) - 但如果唯一可能的方法是单独使用.pm 文件,我也想知道。

那么,有没有一种技术可以用于这样的事情?

【问题讨论】:

    标签: perl inheritance overriding


    【解决方案1】:

    好吧,老实说,我不知道发生了什么,但我浏览了上面的代码,似乎只需要从use IO::All::File 语句中删除-base;否则代码似乎可以按我的预期工作 - 也就是说,包 确实 得到“覆盖” - 如果您在上面的代码中更改此 sn-p:

    # ...
    { # no more recursive inheritance!? IO::All::File gets overriden with this?!
      package IO::All::File;
      use IO::All::File; # -base; # just do not use `-base` here?!
    
      # hacks work if directly in /usr/local/share/perl/5.10.1/IO/All/File.pm
    
      field mtimef => undef; # hack
    
      sub file {
        my $self = shift;
        bless $self, __PACKAGE__;
        $self->name(shift) if @_;
        $self->mtimef($self->mtime); # hack
        print("!! *haxx0rz'd* file() reporting in\n");
        return $self->_init;
      }
    
      1;
    }
    # ...
    

    我觉得这太不可思议了,我什至在其中添加了print() 以确保它是运行的“覆盖”函数,果然,它是;这是我在输出中得到的:

    ...
    !! *haxx0rz'd* file() reporting in
    $VAR1 = {
              '_utf8' => 1,
              'mtimef' => 1394828707,
              'constructor' => sub { "DUMMY" },
              'is_open' => 0,
              'io_handle' => undef,
              'name' => './test.blg',
              '_encoding' => 'utf8',
              'package' => 'IO::All'
            };
    ...
    

    ...果然,字段也在那里,正如预期的那样...

    嗯 - 我希望最终有人在这里提出更合格的答案;目前,我希望这可以解决我的问题:) ...

    【讨论】:

    • Perl 类是“开放的”。也就是说,一旦它们被完全声明,仍然可以向它们添加方法。 (或者重新定义现有方法,尽管use warnings 会警告你这样做。)这就是这里发生的一切。
    • 谢谢你,@tobyink - 非常感谢。干杯!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-06-28
    • 1970-01-01
    • 2017-02-16
    • 1970-01-01
    • 1970-01-01
    • 2018-01-04
    • 2014-06-16
    相关资源
    最近更新 更多