KJ7*_*LNW 1 perl module subclass vectorization
我正在编写一个封装父类的多个对象的子类,这样我就可以像向量一样调用函数,如下所示:
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;
Run Code Online (Sandbox Code Playgroud)
我不想NewClass为 中的每个函数编写新的向量化函数OriginalClass,特别是当OriginalClass添加要在 中维护(向量化)的新函数时NewClass。
问题:
据我了解,AUTOLOAD速度很慢,那么有没有一种方法可以OriginalClass通过类似NewClasswithout之类的方式对调用进行矢量化AUTOLOAD?
据我了解
AUTOLOAD很慢
如果AUTOLOAD生成丢失的子程序,则只有第一个调用是“慢”的,因为同一方法的后续调用根本不会导致AUTOLOAD被调用。
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
Run Code Online (Sandbox Code Playgroud)
请注意,我没有使用parentand SUPER::。这不是继承关系。并且它会阻止AUTOLOAD被调用,因为AUTOLOAD仅当方法不存在时才被调用。
您可以使用 Sub::Name 来“命名子进程”以便更好地进行诊断。
use Sub::Name qw( subname );
my $method = subname $method_name => sub { ... };
Run Code Online (Sandbox Code Playgroud)
但是,是的,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
Run Code Online (Sandbox Code Playgroud)
上面使用了硬编码列表,但更动态的解决方案是可能的。例如,可以通过检查 OriginalClass 命名空间中的 subs 内容来获取该列表(过滤掉new任何其他不合适的内容,例如以 开头的名称_)。