【发布时间】:2021-10-04 12:51:56
【问题描述】:
我有一系列为我的脚本执行输出功能的模块。有时会直接调用模块——它被称为View——有时会使用扩展它的子类(View::ChildName)。 View 在加载时声明our $THEMENAME = 'default';,而子视图在加载时声明自己特定的$THEMENAME。
问题:在子主题上调用new() 时,它会调用my $self = $class->next::method(%params);(使用mro)来获取父类设置的一些核心内容,然后再对其进行扩展。核心位之一是父类设置$self->{'themeName'}。但是,如果它只是调用$THEMENAME,它会获取父级的设置:“默认”。
我可靠且成功地解决此问题的唯一方法是暂时关闭 strict 并执行以下操作:
my $packName = ref $self;
{
no strict;
$self->{'themeName'} = ${${packName} . "::THEMENAME"};
}
这可行,但在分析代码时,如果频繁创建对象,这实际上会增加比我预期的更多的开销。我尝试了始终使用父包名称的替代方法,例如孩子设置$View::THEMENAME。这有效,但前提是主题名称设置在new 内,而不是在模块加载时;如果它正在加载,如果在脚本过程中创建了几个不同的子对象(不同的子对象),则会出现不稳定的行为。
这些选项似乎都不太理想。有没有好的方法来做到这一点?我发现的唯一一件事是this old question,我认为合并Moo 可能会增加比我通过摆脱当前no strict 块来避免的更多开销。是否在更现代的 Perl 版本中添加了任何可以解决我的问题的内容?
另一种方法是一起避开这个问题,只需在每个子对象的 new 方法中设置 $self->{'themeName'},尽管我试图避免这种变化,因为有相当多的遗留子类期望 $THEMENAME存在。
View.pm 的最小可重现示例:
use strict;
package View;
our $THEMENAME = 'default';
sub new {
my $class = shift;
my $params = shift;
my $self = { 'setting' => $params{'setting'} };
bless $self, $class;
$self->{'themeName'} = $THEMENAME;
return $self;
}
View/Child.pm:
use strict;
use mro;
package View::Child;
use parent 'View';
our $THEMENAME = 'child';
sub new {
my $class = shift;
my $params = shift;
my $self = $class->next::method($params);
bless $self, $class;
say STDOUT $self->{'themeName'};
# Prints 'default' not 'child'.
return $self;
}
现在是一个脚本来调用它:
use View::Child;
my $object = View::Child->new();
如果您将第一个代码块添加到 View.pm,它会给出预期的结果,但似乎每次调用 new 会增加大约 9 毫秒 - 超过它处理其他所有事情所需的时间我有更长的全长new 方法——如果程序运行多次迭代,它会加起来:
use strict;
package View;
our $THEMENAME = 'default';
sub new {
my $class = shift;
my $params = shift;
my $self = { };
bless $self, $class;
my $packName = ref $self;
{
no strict;
$self->{'themeName'} = ${${packName} . "::THEMENAME"};
}
return $self;
}
【问题讨论】:
-
你能添加一个最小的可运行示例吗?这将有助于澄清你的问题。见minimal reproducible example
-
@HåkonHægland 我添加了一个。谢谢!
-
此行在您当前的示例中返回
undef:my $self = $class->next::method($params); -
哦!我在描述文件时混淆了文件名的符号,我认为:应该是
View/Child.pm而不是View::Child.pm。也许这就是问题? (对于演示代码,不是我的问题。) -
为什么不能在调用了父构造函数后,在子构造函数中设置主题名称?