我正在编写一个子类,它封装父类的多个对象,这样我就可以像向量一样调用函数,比如:
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
请注意,我没有使用parent
和SUPER::
。这不是继承关系。它将阻止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可能会有所帮助:它将方法调用委托给一组对象。