【问题标题】:Perl Moose add instance attribute not class attributePerl Moose 添加实例属性而不是类属性
【发布时间】:2014-12-07 01:28:01
【问题描述】:

我需要为 Moose 类实例添加属性。在下面的代码中,当我创建 Child 类的实例并向其添加属性“app”时,我发现在创建下一个实例时也添加了此属性。我做错了什么,我再次需要每个创建实例的属性。

#!C:\perl\bin\perl.exe
#!/usr/bin/perl

use v5.10;
use Moose;
use Data::Dumper;

{
    package Child;

    use Moose;
    use utf8;

    sub name {
        say "My name is Richard";
    }
}

sub add_attribute {
    my ($object, $attr) = @_;

    my $meta = $object->meta;

    if (!$object->can("app")) {
        $meta->add_attribute(app => (is => 'rw', default => sub{$attr}));
        $object->app($attr);
    }
    else {
        #$object->app($attr);
        say "attr $attr already exists: object=". ref($object) . ", attr=".($object->app);
    }
}

my $child = Child->new;
$child->name;
add_attribute($child, "First");
say "Child Attr: " . $child->app;
say "";
say Dumper($child);

my $child1 = Child->new;
$child1->name;
#add_attribute($child1, "Second");
say "Child1 Attr: " . $child1->app;
say Dumper($child1);
#say Dumper($child1->meta);

输出:

My name is Richard
Child Attr: First

$VAR1 = bless( {
                 'app' => 'First'
               }, 'Child' );

My name is Richard
Child1 Attr: First
$VAR1 = bless( {
                 'app' => 'First'
               }, 'Child' );

【问题讨论】:

  • 您打算如何在实例上创建方法?在基于类的对象系统的上下文中这意味着什么?
  • 据我了解,Moose 属性存储在对象实例中的散列中,所以如果我在第一个实例中添加一个属性,为什么这个属性也存在于下一个创建的实例中?我的问题现在清楚了吗?

标签: perl moose


【解决方案1】:

诀窍是创建原始类的新子类,为其添加属性,然后将实例重新分配到新子类中。这是一个例子:

use v5.14;

package Person {
  use Moose;
  has name => (is => 'ro');
}

sub add_attribute {
  my ($obj, $name, $value) = @_;
  my $new_class = Moose::Meta::Class->create_anon_class(
    superclasses => [ ref($obj) ],
  );
  $new_class->add_attribute($name, is => 'rw');
  $new_class->rebless_instance($obj, $name => $value);
}

my $alice  = Person->new(name => 'Alice');
my $bob    = Person->new(name => 'Bob');

add_attribute($alice, foot_size => 6);

say $alice->foot_size;

say $bob->foot_size;  # dies, no such method

【讨论】:

  • 问题是,如果 Moose 将属性存储在对象内部的哈希中,为什么要添加到所有实例的属性,这些是类范围属性还是实例属性?
  • Moose 将属性 values 存储在对象的散列中,但是访问这些值的 methods 被添加到类中,因此可以调用类的任何实例。例如,爱丽丝脚尺寸的“6”存储在爱丽丝的散列中。但是 getter/setter 方法已添加到 Alice 的类中,因此同一类的任何其他对象也可以具有脚大小(可能小于或大于“6”)。这就是为什么我们需要将 Alice 拉入一个新类以阻止 Bob 也获取 foot_size 方法。
  • 是的,我现在明白了,你说的很清楚。但是为什么这种技术,不是很糟糕,它应该只在我们调用对象上的元时才被添加到请求的实例中。
  • 这正是 Perl 中方法分派的工作方式。 (实际上是大多数 OO 语言!)当您调用一个方法时,该语言的运行时首先查看对象的类以提供该方法的定义,然后按顺序查看任何父类。
  • 比较“Self”和“Smalltalk”,看看原型系统和基于类的系统的区别 -en.wikipedia.org/wiki/Self_programming_language
猜你喜欢
  • 2020-03-12
  • 1970-01-01
  • 1970-01-01
  • 2013-10-01
  • 1970-01-01
  • 2020-07-26
  • 2018-08-04
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多