为什么在 BUILD 中修改 Moose 类会导致此错误?
我在使用 BUILD
时遇到了与 Moose 相关的错误。当我更改为 BUILDALL
时,它似乎可以工作。请注意 Class::MOP::load_class
的使用
使用 BUILD
Perl version: 5.012002
Class::MOP::Version: 1.11
Moose::Version: 1.24
Applying fixup GV::WebServer::Fixups::Development
aflott-g3 at a.pl line 83.
Error: trying to call refresh() in GV::WebServer::Fixups::Development produced: The 'add_attribute' method cannot be called on an immutable instance at /opt/cidc-perl/perl-5.12.2/lib/perl5/x86_64-linux/Class/MOP/Class/Immutable/Trait.pm line 32
Class::MOP::Class::Immutable::Trait::_immutable_cannot_call('add_attribute') called at /opt/cidc-perl/perl-5.12.2/lib/perl5/x86_64-linux/Class/MOP/Class/Immutable/Trait.pm line 37
Class::MOP::Class:::around('CODE(0x13a2e028)', 'Class::MOP::Class::Immutable::Moose::Meta::Class=HASH(0x13d58...', 'architecture', 'is', 'ro', 'isa', 'Str', 'lazy', 1, ...) called at /opt/cidc-perl/perl-5.12.2/lib/perl5/x86_64-linux/Class/MOP/Method/Wrapped.pm line 159
Class::MOP::Method::Wrapped::__ANON__('Class::MOP::Class::Immutable::Moose::Meta::Class=HASH(0x13d58...', 'architecture', 'is', 'ro', 'isa', 'Str', 'lazy', 1, 'default', ...) called at /opt/cidc-perl/perl-5.12.2/lib/perl5/x86_64-linux/Class/MOP/Method/Wrapped.pm line 89
Class::MOP::Class::Immutable::Moose::Meta::Class::add_attribute('Class::MOP::Class::Immutable::Moose::Meta::Class=HASH(0x13d58...', 'architecture', 'is', 'ro', 'isa', 'Str', 'lazy', 1, 'default', ...) called at a.pl line 47
Amethyst::SystemInfo::BUILD('Amethyst::SystemInfo=HASH(0x13e83010)', 'HASH(0x13e50cc0)') called at generated method (unknown origin) line 147
Amethyst::SystemInfo::new('Amethyst::SystemInfo') called at a.pl line 92
GV::WebServer::Fixups::AutoSet::set() called at a.pl line 84
GV::WebServer::Fixups::Development::refresh('GV::WebServer::Fixups::Development') called at a.pl line 114
main::__ANON__() called at /opt/cidc-perl/perl-5.12.2/lib/perl5/Try/Tiny.pm line 76
eval {...} called at /opt/cidc-perl/perl-5.12.2/lib/perl5/Try/Tiny.pm line 67
Try::Tiny::try('CODE(0x13e82fe0)', 'Try::Tiny::Catch=REF(0x13e8cd50)') called at a.pl line 118
使用 BUILDALL
:
Perl version: 5.012002
Class::MOP::Version: 1.11
Moose::Version: 1.24
Applying fixup GV::WebServer::Fixups::Development
aflott-g3 at a.pl line 71.
aflott-g3364136 at a.pl line 81.
完整错误
从此代码中:
package Amethyst::SystemInfo;
use v5.10;
use Moose;
use Sys::Hostname qw();
use Sys::HostIP;
use Try::Tiny;
has '_host_ip' => ('is' => 'ro', 'isa' => 'Sys::HostIP', 'default' => sub { Sys::HostIP->new });
has 'eth0_ipv4' => ('is' => 'rw', 'isa' => 'Str',);
has 'ethernet_interfaces' => ('is' => 'rw', 'isa' => 'HashRef',);
has 'hostname' => ('is' => 'ro', 'isa' => 'Str', 'default' => sub { Sys::Hostname::hostname });
sub BUILD {
my ($self) = @_;
$self->ethernet_interfaces($self->_host_ip->interfaces);
if ($self->ethernet_interfaces->{'eth0'}) {
$self->eth0_ipv4($self->ethernet_interfaces->{'eth0'});
}
foreach my $attrib (
qw(architecture domain fqdn kernel kernelrelease kernelversion memorytotal operatingsystem processor processorcount swap)
) {
$self->meta->add_attribute(
$attrib => (
'is' => 'ro',
'isa' => 'Str',
'lazy' => 1,
'default' => sub { return $self->_load_value($attrib) }
)
);
}
$self->meta->make_immutable;
return;
}
sub _load_value {
my ($self, $module_name) = @_;
try {
Class::MOP::load_class("Pfacter::$module_name");
}
catch {
warn("Failed to load Pfacter::$module_name");
};
my $value = "Pfacter::$module_name"->pfact({'pfact' => {'kernel' => 'Linux'}});
unless (defined($value)) {
warn("finding value for $module_name returned undef");
}
chomp($value);
return $value;
}
no Moose;
package GV::WebServer::Fixups::Development;
use v5.10;
sub refresh {
warn Amethyst::SystemInfo->new->hostname;
return GV::WebServer::Fixups::AutoSet::set();
}
package GV::WebServer::Fixups::AutoSet;
use v5.10;
sub set {
my $sysinfo = Amethyst::SystemInfo->new;
warn $sysinfo->hostname, ' ', $sysinfo->swap;
}
package main;
use v5.10;
use Class::MOP;
use Try::Tiny;
my $module_name = "GV::WebServer::Fixups::Development";
say('Perl version: ', $]);
say('Class::MOP::Version: ', $Class::MOP::VERSION);
say('Moose::Version: ', $Moose::VERSION);
say("Applying fixup $module_name");
Class::MOP::load_class($module_name);
my $ret;
try {
$ret = $module_name->refresh;
}
catch {
warn("Error: trying to call refresh() in $module_name produced: " . shift);
};
I'm having trouble with this Moose-related error when using BUILD
. When I change to BUILDALL
it appears to work. Note the use of Class::MOP::load_class
Using BUILD
Perl version: 5.012002
Class::MOP::Version: 1.11
Moose::Version: 1.24
Applying fixup GV::WebServer::Fixups::Development
aflott-g3 at a.pl line 83.
Error: trying to call refresh() in GV::WebServer::Fixups::Development produced: The 'add_attribute' method cannot be called on an immutable instance at /opt/cidc-perl/perl-5.12.2/lib/perl5/x86_64-linux/Class/MOP/Class/Immutable/Trait.pm line 32
Class::MOP::Class::Immutable::Trait::_immutable_cannot_call('add_attribute') called at /opt/cidc-perl/perl-5.12.2/lib/perl5/x86_64-linux/Class/MOP/Class/Immutable/Trait.pm line 37
Class::MOP::Class:::around('CODE(0x13a2e028)', 'Class::MOP::Class::Immutable::Moose::Meta::Class=HASH(0x13d58...', 'architecture', 'is', 'ro', 'isa', 'Str', 'lazy', 1, ...) called at /opt/cidc-perl/perl-5.12.2/lib/perl5/x86_64-linux/Class/MOP/Method/Wrapped.pm line 159
Class::MOP::Method::Wrapped::__ANON__('Class::MOP::Class::Immutable::Moose::Meta::Class=HASH(0x13d58...', 'architecture', 'is', 'ro', 'isa', 'Str', 'lazy', 1, 'default', ...) called at /opt/cidc-perl/perl-5.12.2/lib/perl5/x86_64-linux/Class/MOP/Method/Wrapped.pm line 89
Class::MOP::Class::Immutable::Moose::Meta::Class::add_attribute('Class::MOP::Class::Immutable::Moose::Meta::Class=HASH(0x13d58...', 'architecture', 'is', 'ro', 'isa', 'Str', 'lazy', 1, 'default', ...) called at a.pl line 47
Amethyst::SystemInfo::BUILD('Amethyst::SystemInfo=HASH(0x13e83010)', 'HASH(0x13e50cc0)') called at generated method (unknown origin) line 147
Amethyst::SystemInfo::new('Amethyst::SystemInfo') called at a.pl line 92
GV::WebServer::Fixups::AutoSet::set() called at a.pl line 84
GV::WebServer::Fixups::Development::refresh('GV::WebServer::Fixups::Development') called at a.pl line 114
main::__ANON__() called at /opt/cidc-perl/perl-5.12.2/lib/perl5/Try/Tiny.pm line 76
eval {...} called at /opt/cidc-perl/perl-5.12.2/lib/perl5/Try/Tiny.pm line 67
Try::Tiny::try('CODE(0x13e82fe0)', 'Try::Tiny::Catch=REF(0x13e8cd50)') called at a.pl line 118
Using BUILDALL
:
Perl version: 5.012002
Class::MOP::Version: 1.11
Moose::Version: 1.24
Applying fixup GV::WebServer::Fixups::Development
aflott-g3 at a.pl line 71.
aflott-g3364136 at a.pl line 81.
Full error
From this code:
package Amethyst::SystemInfo;
use v5.10;
use Moose;
use Sys::Hostname qw();
use Sys::HostIP;
use Try::Tiny;
has '_host_ip' => ('is' => 'ro', 'isa' => 'Sys::HostIP', 'default' => sub { Sys::HostIP->new });
has 'eth0_ipv4' => ('is' => 'rw', 'isa' => 'Str',);
has 'ethernet_interfaces' => ('is' => 'rw', 'isa' => 'HashRef',);
has 'hostname' => ('is' => 'ro', 'isa' => 'Str', 'default' => sub { Sys::Hostname::hostname });
sub BUILD {
my ($self) = @_;
$self->ethernet_interfaces($self->_host_ip->interfaces);
if ($self->ethernet_interfaces->{'eth0'}) {
$self->eth0_ipv4($self->ethernet_interfaces->{'eth0'});
}
foreach my $attrib (
qw(architecture domain fqdn kernel kernelrelease kernelversion memorytotal operatingsystem processor processorcount swap)
) {
$self->meta->add_attribute(
$attrib => (
'is' => 'ro',
'isa' => 'Str',
'lazy' => 1,
'default' => sub { return $self->_load_value($attrib) }
)
);
}
$self->meta->make_immutable;
return;
}
sub _load_value {
my ($self, $module_name) = @_;
try {
Class::MOP::load_class("Pfacter::$module_name");
}
catch {
warn("Failed to load Pfacter::$module_name");
};
my $value = "Pfacter::$module_name"->pfact({'pfact' => {'kernel' => 'Linux'}});
unless (defined($value)) {
warn("finding value for $module_name returned undef");
}
chomp($value);
return $value;
}
no Moose;
package GV::WebServer::Fixups::Development;
use v5.10;
sub refresh {
warn Amethyst::SystemInfo->new->hostname;
return GV::WebServer::Fixups::AutoSet::set();
}
package GV::WebServer::Fixups::AutoSet;
use v5.10;
sub set {
my $sysinfo = Amethyst::SystemInfo->new;
warn $sysinfo->hostname, ' ', $sysinfo->swap;
}
package main;
use v5.10;
use Class::MOP;
use Try::Tiny;
my $module_name = "GV::WebServer::Fixups::Development";
say('Perl version: ', $]);
say('Class::MOP::Version: ', $Class::MOP::VERSION);
say('Moose::Version: ', $Moose::VERSION);
say("Applying fixup $module_name");
Class::MOP::load_class($module_name);
my $ret;
try {
$ret = $module_name->refresh;
}
catch {
warn("Error: trying to call refresh() in $module_name produced: " . shift);
};
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
每次构造该类的对象时,您都会修改该类。这没有任何意义。只需将类构造代码从
BUILD
和BUILDARGS
中移出,并将其与其余的类构造代码放在一起即可。感谢 phaylon 和 bvr。
You are modifying the class every time you construct an object of that class. That makes no sense. Just move your class construction code out of
BUILD
andBUILDARGS
and place it with the rest of the class construction code.Kudos to phaylon and bvr.