为什么在 BUILD 中修改 Moose 类会导致此错误?

发布于 2024-10-25 14:33:50 字数 5033 浏览 5 评论 0原文

我在使用 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

随心而道 2024-11-01 14:33:50

每次构造该类的对象时,您都会修改该。这没有任何意义。只需将类构造代码从 BUILDBUILDARGS 中移出,并将其与其余的类构造代码放在一起即可。

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 });

foreach my $attrib (qw(
    architecture domain fqdn kernel kernelrelease kernelversion
    memorytotal operatingsystem processor processorcount swap
)) {
    has $attrib => (
        'is'      => 'ro',
        'isa'     => 'Str',
        'lazy'    => 1,
        'default' => sub { return $_[0]->_load_value($attrib) },
    );
}

sub BUILD {
    my ($self) = @_;

    $self->ethernet_interfaces($self->_host_ip->interfaces);

    if ($self->ethernet_interfaces->{'eth0'}) {
        $self->eth0_ipv4($self->ethernet_interfaces->{'eth0'});
    }
}

sub _load_value {
    ...
}

no Moose;
__PACKAGE__->meta->make_immutable;

1;

感谢 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 and BUILDARGS and place it with the rest of the class construction 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 });

foreach my $attrib (qw(
    architecture domain fqdn kernel kernelrelease kernelversion
    memorytotal operatingsystem processor processorcount swap
)) {
    has $attrib => (
        'is'      => 'ro',
        'isa'     => 'Str',
        'lazy'    => 1,
        'default' => sub { return $_[0]->_load_value($attrib) },
    );
}

sub BUILD {
    my ($self) = @_;

    $self->ethernet_interfaces($self->_host_ip->interfaces);

    if ($self->ethernet_interfaces->{'eth0'}) {
        $self->eth0_ipv4($self->ethernet_interfaces->{'eth0'});
    }
}

sub _load_value {
    ...
}

no Moose;
__PACKAGE__->meta->make_immutable;

1;

Kudos to phaylon and bvr.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文