2

在我的最后一个问题中,我问了许多不相关的事情,并且不能接受多个答案,只回答一些问题,所以这里明确(我希望)定义了关于(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不包含所有包变量相关联时?)驼鹿从哪里知道它?)
  • 在 Moo 的情况下如何获取 all_attributes?

显然我错过了一些基本知识.. :(

4

1 回答 1

0

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

每次创建一个新对象时,例如SomeMoo->new创建一个新的引用,它由两部分组成,第一部分是数据,通常是 hashref,hashref 由第二部分祝福,即类,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或通过设置它们$omoo->a1("someValue").

正如 ikegami 所提到的,default => undef在您的has语句中添加类似:将导致 Moo/Moose 在第一次构造对象时实例化该值。

我希望这能解释如何$self包含对象数据,它只包含以前由方法或构造函数设置的键。

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

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

package SimpleMoo;
use Moo;
our @attr_list;
sub my_has {push @attr_list, $_[0]; has @_}
sub get_all_attributes {@attr_list}
my_has $_ => ( is => 'rw', predicate => 1) for (qw(a1 a2 nn xx));

package main;
my $omoo = SimpleMoo->new();
say $_ for $omoo->get_all_attributes;

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

最终,您使用的是 Moose 和 Moo,您不应该检查底层对象,这两个模块都使用魔法(符号表修改和类继承等),并且您不能依赖底层对象或类本身来拥有您希望他们拥有的属性和方法。如果您有一个用例想要列出类上定义的每个属性,请使用 Moose 并检查元类,或者通过自己手动定义来控制您的类。

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

于 2015-04-30T12:54:16.587 回答