在Perl中,可以在没有"AUTOLOAD"的情况下对所有父类函数进行子类化和挂钩吗



我正在编写一个子类,它封装父类的多个对象,这样我就可以像向量一样调用函数,比如:

package OriginalClass;
sub new { return bless {bar => 123}, 'OriginalClass' }
sub foo { return shift->{bar}; }
1;

package NewClass;
use parent OriginalClass;
# Return a blessed arrayref of "OriginalClass" objects.
# new() would be called NewClass->new(OriginalClass->new(), ...)
sub new { 
my $class = shift;
return bless @_, 'NewClass';
}
# Vectorized foo(), returns a list of SUPER::foo() results:
sub foo
{
my $self = shift;
my @ret;
push @ret, $_->SUPER::foo() foreach @$self;
return @ret;
}
1;

我不想在NewClass中为OriginalClass中的每个函数编写新的矢量化函数,特别是当OriginalClass添加了要在NewClass中维护(矢量化(的新函数时。

问题:

据我所知,AUTOLOAD很慢,那么有没有一种方法可以在没有AUTOLOAD的情况下,通过类似NewClass的方式来矢量化调用OriginalClass

据我所知,AUTOLOAD是慢速

如果AUTOLOAD生成丢失的子,则只有第一个调用是";"慢";因为相同方法的后续调用根本不会导致CCD_ 11被调用。

package NewClass;
use strict;
use warnings;
sub new {
my $class = shift;
return bless( @_, $class );
}
sub AUTOLOAD {
my $method_name = our $AUTOLOAD =~ s/^.*:://sr;
my $method = sub {
my $self = shift;
return map { $_->$method_name( @_ ) } @$self;
};
{
no strict 'refs';
*$method_name = $method;
}
goto &$method;
}
1

请注意,我没有使用parentSUPER::。这不是继承关系。它将阻止AUTOLOAD被调用,因为AUTOLOAD只有在方法不存在时才被调用。

您可以使用Sub::Name来"命名子";以便进行更好的诊断。

use Sub::Name qw( subname );
my $method = subname $method_name => sub { ... };

但是,这里可以避免AUTOLOAD,只要您可以提前获得方法名称的列表。

package NewClass;
use strict;
use warnings;
sub new {
my $class = shift;
return bless( @_, $class );
}
for my $method_name (qw( foo ... )) {
my $method = sub {
my $self = shift;
return map { $_->$method_name( @_ ) } @$self;
};
no strict 'refs';
*$method_name = $method;
}
1

上面使用了一个硬编码列表,但也可以使用更动态的解决方案。例如,该列表可以通过检查OriginalClass命名空间中的子名称(过滤掉new和任何其他不合适的名称,例如以_开头的名称(来获得。

模块https://metacpan.org/pod/Array::Delegate可能会有所帮助:它将方法调用委托给一组对象。

最新更新