Moo / Moose属性 - “key%$ self”的工作原理如何?

时间:2014-08-26 21:12:38

标签: perl moose moo

在我的last question中,我问了许多不相关的事情,并且不能接受多个答案,只回答了一些问题,所以这里显然(我希望)定义了关于(Moo)属性的问题。

use 5.010;
use strict;
use warnings;

package SomeMoo;
use Moo;
has $_ => ( is => 'rw', predicate => 1) for (qw(a1 a2 nn xx));

package SomeMoose;
use Moose;
has $_ => ( is => 'rw', predicate => "has_".$_) for (qw(a1 a2 nn xx));

package main;
use Data::Dumper;
my $omoo   = SomeMoo->new(a1 => "a1val", a2 => "a2val", xx=>"xxval");
say Dumper $omoo;

# $VAR1 = bless( {
#                 'a2' => 'a2val',
#                 'a1' => 'a1val',
#                 'xx' => 'xxval'
#               }, 'SomeMoo' );

#for Moose:  
my $omoose = SomeMoose->new(a1 => "a1val", a2 => "a2val", xx=>"xxval");
say Dumper $omoose;
#as above, only blessed to package 'SomeMoose'.

#in both cases can do the next, for getting an (partial) list "attributes"
say $_ for keys (%$omoose); #or %$omoo

#anyway, in Moose i can
say "all attributes";
say $_->name for $omoose->meta->get_all_attributes();

#what prints
# all attributes
# nn
# a2
# a1
# xx

所以祝福的对象重新引用了一个只包含所设置属性的对象。

问题:

  • 为什么$self引用,(所以%$self只包含) 属性是什么,而不是全部,例如nn 码? (当bless仅将referencepackage相关联时,为什么$omoo不包含所有包变量?)并且Moose从哪里知道它?)
  • 如何在Moo的情况下获取all_attributes?

显然我缺少一些基本知识.. :(

1 个答案:

答案 0 :(得分:0)

  

为什么$ self引用(所以%$ self conatains)只有所设置的属性,而不是全部,例如nn来自示例代码? (当祝福只将引用与包相关联时,为什么$ omoo不包含所有包变量?)并且Moose从哪里知道它?)

每次创建一个新对象(例如SomeMoo->new)时,都会创建一个由两部分组成的新引用,第一部分是数据,通常是hashref,hashref由第二部分祝福part,即类SomeMoo。哈希用于存储与此新对象实例关联的数据,而SomeMoo是提供与访问/操作/处理数据相关的方法的类。

在您的类定义中,您调用一个名为has的函数。此函数使用新方法扩展类。在Moo的情况下,你可以通过写下类似的东西来制作一个穷人的版本。

package SimpleMoo;
no strict 'refs';

sub new {bless {}, $_[0]} # very very simple constructor (oldskool)

*{__PACKAGE__."::$_"} = sub {              # fyi: __PACKAGE__ eq "SimpleMoo"
    $_[0]->{$_} = $_[1] if exists $_[1];
    return $_[0]->{$_};
} for qw(a1 a2 nn xx);

上面将我们所有的方法添加到SimpleMoo类中,它通过操作符号表来实现,并且可能与Moo完全接近(除了Moo / Moose扩展了类继承的元类),一个偶数更简单的例子是手动定义访问器:

package SimpleMoo;

sub new {bless {}, $_[0]} # very very simple constructor (oldskool)

sub a1 {
    my ($self) = shift;
    $self->{a1} = $_[0] if exists $_[0]; # set value if provided
    return $self->{a1}; # return the value
}
sub a2 {
    my ($self) = shift;
    $self->{a2} = $_[0] if exists $_[0]; # set value if provided
    return $self->{a2}; # return the value
}
# ... copy and paste the for nn and xx ...

从上面的示例中可以看出,我使用允许您从哈希设置和获取值的方法扩展该类,但不是隐式地将哈希结构设置为对象构造函数的一部分(如果你想这样做,应该在new内进行 - 就像Moo和Moose一样。

这意味着通过类似keys %$omoo之类的内容检查对象,在设置之前不会显示任何密钥(通过调用->new或将其设置为{ {1}}。

如ikegami所述,在$omoo->a1("someValue")语句中添加类似default => undef的内容将导致Moo / Moose在首次构造对象时实例化该值。

我希望这能解释has如何包含对象数据,该对象数据仅包含先前由方法或构造函数设置的键。

  

如何在Moo的情况下获取all_attributes?

不幸的是,Moo api没有提供列出所有已定义属性的方法,因此我无法提供支持的解决方案,但我可以提供众多(非完美的非完全推荐)解决方案中的一种:

$self

我确信Moo的某个人能够提供更好的方式来访问Moo中使用的元类来获取此列表。但我确定不推荐任何一种解决方案。

最终,你正在使用Moose和Moo,你不应该检查底层对象,两个模块都使用魔术(符号表修改和类继承,以及所有种类),你不能依赖底层对象,也不能class本身具有您期望它们具有的属性和方法。如果你有一个用例,你要列出在类上定义的每个属性,请使用Moose并检查元类,或者通过手动定义来控制你的类。

您还应该考虑为什么需要来自对象的属性列表,也许您可​​以自己列出它们?如果有人从你的班级继承了怎么办?或者你决定混合一个角色?这会破坏试图利用对象上的属性列表的代码吗?