***************************************************** * GENERATED FILE, DO NOT EDIT * * THIS IS NO SOURCE FILE, BUT RESULT OF COMPILATION * ***************************************************** This file was generated by po4a(7). Do not store it (in VCS, for example), but store the PO file used as source file by po4a-translate. In fact, consider this as a binary, and the PO file as a regular .c file: If the PO get lost, keeping this translation up-to-date will be harder. =encoding UTF-8 =pod =head1 NAME Moose::Manual::Attributes - Moose 对象的属性 =head1 VERSION version 2.0401 =head1 介绍 Moose 中最强大也最灵活的功能莫过于对象的属性。通过简单的声明属性便可以构造一个功能强大的类。 类的每一个成员都是一个属性。比如,C 类有 first name 和 last name。属性对于类是可选的,好比并不是每一个 C 类都有社保号。 我们可以把类属性当作是成员的名字,通过这个名字我们可以读取或设置该成员的值。当然,属性还可以包括默认值、类型约束、委托方法等等。 在其他语言中,属性也被称为 slots 或 properties。 =head1 属性设置 通过 C 来声明一个属性: package Person; use Moose; has 'first_name' => ( is => 'rw' ); 这样就声明了有一个可读写的属性的类 C。 =head2 读写 vs 只读 通过 C 传递的选项可以对属性进行相关设置。不过最简单也是最基本的是,你可以通过 C 来设置变量的读取权限,read-only(ro) 或者 read-write(rw)。当设置为rw 时,你可以通过访问器来修改它的值。但设置为 ro时,你便只能读取该属性的值。 事实上,你可以不设置 C,Moose 会默认使该属性没有任何存取权限。这对某些属性比较管用,如句柄等。但是 Moose 会抛出警告以防止程序员忘记书写存取规则。如果你确实需要这么做,那么可以通过设置 C 为 C 来防止产生警告。 =head2 存取方法 每个属性有一个或多个存取方法,通过存取方法,你可以读取或者设置该属性的值 默认的存取方法和属性的名字一样。如果属性存取权限设置为 rw,则可以通过存取方法来读写属性值,反之,则不可以。 以上面的 C 类为例,我们有一个存取方法为 C,通过这个存取方法我们可以读取或设置 C 实例的 C 属性。 如果你愿意的话,你也可以指定具体的方法来进行存取操作。这对于你想要设置一个默认存取权限为 ro,但是可以通过某种方法来修改属性是非常方便的。 has 'weight' => ( is => 'ro', writer => '_set_weight', ); 这在以下场景中是非常方便的。比如,每当我们调用 C 方法的时候,我们可能会改变 weight,而在其他场景中我们对 weight 只有读取权限。 有些人喜欢把读取和设置方法分别来声明。在 I 中,Damian Conway也推荐读者使用"get_"和"set_"类方法。 我们可以通过具体的声明来做到。 has 'weight' => ( is => 'rw', reader => 'get_weight', writer => 'set_weight', ); 你认为这样一遍又一遍非常繁琐?你说的对,不过幸运的是,Moose 提供了相当强大的拓展系统,可以让你覆盖默认的命名约定。有关详细信息,请参阅 L。 =head2 断言和清理方法 Moose 允许你使用断言来判断一个属性是否已经被定义。 断言方法可以告诉你当前属性是否被定义。不过需要注意的是,当属性被设置为 C或者其他的一些假值,断言依然会返回 true。 清理方法会取消设置属性。这和设置属性为 C 是 I<不同的>。清理函数是为了让你更方便的使用断言。 这里有一个例子用来讲解断言和清理方法。 package Person; use Moose; has 'ssn' => ( is => 'rw', clearer => 'clear_ssn', predicate => 'has_ssn', ); ... my $person = Person->new(); $person->has_ssn; # false $person->ssn(undef); $person->ssn; # returns undef $person->has_ssn; # true $person->clear_ssn; $person->ssn; # returns undef $person->has_ssn; # false $person->ssn('123-45-6789'); $person->ssn; # returns '123-45-6789' $person->has_ssn; # true my $person2 = Person->new( ssn => '111-22-3333'); $person2->has_ssn; # true 默认情况下,Moose 不为你提供断言和清理方法。当你具体指明时,Moose 会为你提供的。 =head2 必需? 默认情况下,所有的属性都是可选的,不需要在构造对象的时候就明确给出。如果你想指明某个属性是必须的,你可以把 C 属性设置为 true。 has 'name' => ( is => 'ro', required => 1, 值得一提的是,什么时候才是"required"。 基本上,当这个属性名必须被提供给构造函数,或者通过 default、builder来设置,这种情况下是 required。 如果你在一个必须属性上定义了清理方法,这个清理方法是I<可以>运行的,也就是说一个必须属性也是可以被取消设置的。 但是这样做大多是没有意义的,所以我们并不推荐这么做。 =head2 默认值和构造方法 属性可以设置默认值,而且 Moose 提供了两种方法来设置默认值。 最简单的,你可以通过 C 来设置。 has 'size' => ( is => 'ro', default => 'medium', predicate => 'has_size', ); 如果 size 属性没有提供给构造函数,那么 size 属性会被设置为默认值 C: my $person = Person->new(); $person->size; # medium $person->has_size; # true 你也可以通过提供一个子函数来提供默认值。 has 'size' => ( is => 'ro', default => sub { ( 'small', 'medium', 'large' )[ int( rand 3 ) ] }, predicate => 'has_size', ); 这是一个简单的例子。每次初始化构建默认值的时候,子函数便会被调用。 当你提供子函数引用时,Moose 会调用它,并且不传递任何参数进去。 has 'size' => ( is => 'ro', default => sub { my $self = shift; return $self->height > 200 ? 'large' : 'average'; }, ); C 是在构造函数中开始运行的,所以会比一些属性更先运行。但当 C依赖其他属性时就会出现一些问题。不过你可以通过设置属性为 C 来解决。这个会在之后讲到。 如果你想在 default 中使用引用的话,这个引用必须在子函数中返回。 has 'mapping' => ( is => 'ro', default => sub { {} }, ); 这是必要的。否则 Perl 会实例化一次,然后该引用在各个实例中被共享。下面这个是错误的。 has 'mapping' => ( is => 'ro', default => {}, # wrong! ); 如果你赋给 default 一个非子函数返回的引用时,Moose 会抛出一个错误。 If Moose allowed this then the default mapping attribute could easily end up shared across many objects. Instead, wrap it in a subroutine reference as we saw above. 这有一点古怪,不过请原谅,Perl 有时候就是这样。 你可以通过 C 方法来避开这一古怪的现象。 has 'size' => ( is => 'ro', builder => '_build_size', predicate => 'has_size', ); sub _build_size { return ( 'small', 'medium', 'large' )[ int( rand 3 ) ]; } 这个使用有以下几个好处。把对属性的操作移到一个代码块中,方便阅读与组织。这样子使用的话,也方便子类重载或者由一个 role 来实现。 我们强烈建议你使用 C 来初始化属性。它就是 C 的增强版。 C 和 C 作为类方法调用的,不接受额外的参数。 =head3 Builders 覆写 C 是通过名字来指定初始化函数的。所以 builder 方法是可以被继承和重载的。 比如我们继承 C 类,我们便可以重载 C<_build_size>: package Lilliputian; use Moose; extends 'Person'; sub _build_size { return 'small' } =head3 Builders 与 roles 配合工作 同样,builders 可以与 roles 完美的配合。比如,一个角色可以为一个类提供 builder方法。 package HasSize; use Moose::Role; requires '_build_size'; has 'size' => ( is => 'ro', lazy => 1, builder => '_build_size', ); package Lilliputian; use Moose; with 'HasSize'; sub _build_size { return 'small' } 关于 Roles 的更多信息可以查阅 L。 =head2 Laziness Moose 允许你通过 C 来推迟属性定义。 has 'size' => ( is => 'ro', lazy => 1, builder => '_build_size', ); 当某属性 C 为 true 时,该属性的 default 并不会在构造实例时运行,而是在相应的访问器访问时才进行计算。为什么要这样做呢? 首先,如果该属性的 default 值依赖于其他属性,那么该属性的 C I<必须>为 true。 有一些情况下是不需要在该属性被请求前进行计算的。通过设置该属性为 C,你可以有效的节省你的 CPU 时间。 我们建议你使用 builder 或者 lazy default。 =head2 构造函数的参数(C) 默认情况下,每个属性都可以通过名字传递给类。有时,你可能需要用一个略有不同的名字,或者你不想传递任何参数进去。 你可以通过 C 选项来做到以上的事情。 has 'bigness' => ( is => 'ro', init_arg => 'size', ); 现在我们有一个"bigness"属性,但是我们通过 C 来传递到构造函数中。 你也可以通过如下方式设置不接受任何参数。 has '_genetic_code' => ( is => 'ro', lazy => 1, builder => '_build_genetic_code', init_arg => undef, ); By setting the C to C, we make it impossible to set this attribute when creating a new object. =head2 循环引用 Moose 内置是支持 weak reference 的,可以通过设置 C 为 true 来实现。 has 'parent' => ( is => 'rw', weak_ref => 1, ); $node->parent($parent_node); 这对你构建一个包含循环引用的类是非常有用的。 When the object in a weak references goes out of scope, the attribute's value will become C "behind the scenes". This is done by the Perl interpreter directly, so Moose does not see this change. This means that triggers don't fire, coercions aren't applied, etc. 该属性并没有被清楚,所以在调用断言方法时,仍然返回 true。(这里有点含糊不清,具体的请见原文档) =head2 触发器 C 将在属性被设置的时候自动被调用。 has 'size' => ( is => 'rw', trigger => \&_size_set, ); sub _size_set { my ( $self, $size, $old_size ) = @_; my $msg = $self->name; if ( @_ > 2 ) { $msg .= " - old size was $old_size"; } $msg .= " -size is now $size"; warn $msg; } 当属性被设置之后,触发器将会被调用。Moose 会传递新值、旧值进去,当没有旧值时,旧值参数为 C。 这个与 C 方法修饰符是有区别的。触发器只在属性被设置时被调用,而不是每当访问器访问时触发。触发器也会在构造函数运行时被调用。而 C 方法修饰符不是。 注意,触发器不在 C 或 C 之后被调用。 =head2 属性类型 属性类型可以限制只接受某些类型的值: has 'first_name' => ( is => 'ro', isa => 'Str', ); 这表明 C 属性是字符串类型。 Moose 还提供了一个快捷的方法来指定一个属性的类型,就是通过一个 role 来实现的。 has 'weapon' => ( is => 'rw', does => 'MyApp::Weapon', ); 关于属性类型的信息具体请查阅 L。 =head2 委托属性 Moose 可以定义委托属性来操作属性值。 has 'hair_color' => ( is => 'ro', isa => 'Graphics::Color::RGB', handles => { hair_color_hex => 'as_hex_string' }, ); 当调用 C 时,会实际上调用 C<<$self->hair_color->as_hex_string>>。 关于委托属性的更多信息请查阅 L。 =head2 属性特征和元类 Moose 最好的特点就是可以通过 traits 和 元类来实现自省。 你可以提供一个或多个 traits 来描述一个属性: use MooseX::MetaDescription; has 'size' => ( is => 'ro', traits => ['MooseX::MetaDescription::Meta::Trait'], description => { html_widget => 'text_input', serialize_as => 'element', }, ); 你可以很方便的使用一个或多个 traits。 关于属性特征和元类的许多模块都可以在 CPAN 上找到。你可以在L 中找到一些示例。关于"元类"和"继承"的更多信息请查阅 L。 =head2 定义自己的委托属性 Native delegations 允许你定义 Perl 的数据结构。 比如,我们可以创建关于数组引用的 C,C,C,C等方法。 has 'options' => ( traits => ['Array'], is => 'ro', isa => 'ArrayRef[Str]', default => sub { [] }, handles => { all_options => 'elements', add_option => 'push', map_option => 'map', option_count => 'count', sorted_options => 'sort', }, ); 更多信息请查阅 L。 =head1 属性继承 默认情况下,子类可以继承父类中所有的属性。你也可以在子类中重载它们。 继承一个属性,只需要简单的在前面加(C<+>): package LazyPerson; use Moose; extends 'Person'; has '+first_name' => ( lazy => 1, default => 'Bill', ); 现在子类中的 C 属性是 lazy 的,而且默认值为 C<'Bill'>。 我们建议你在不是很了解的时候不要随便使用,尤其是涉及到类型(C)的时候。 =head1 多属性快捷创建 如果你有大量的属性仅仅是名字不同,你可以一次性的声明它们。 package Point; use Moose; has [ 'x', 'y' ] => ( is => 'ro', isa => 'Int' ); 因为 C 也是一个函数,所以你也可以通过循环来创建。 for my $name ( qw( x y ) ) { my $builder = '_build_' . $name; has $name => ( is => 'ro', isa => 'Int', builder => $builder ); } =head1 更多 Moose 属性是一个 big topic,而这个文档只包含了一部分。我们建议你继续阅读L 和 L 来更全面的了解属性。 =head1 更多的选项信息 Moose 属性有许多选项。下面列出一些你可能会比较感兴趣的。 =head2 C<文档描述> 你可以为你的属性提供一个文档描述。 has 'first_name' => ( is => 'rw', documentation => q{The person's first (personal) name}, ); Moose 会把该描述存储起来。 =head2 C<序列化数据> 如果你的属性是一段数组引用或者 hash 引用,C 这个设置会让 reader 来访问这个属性时,可以看到序列化以后的内容: my %map = $object->mapping; 当然这仅仅在你的属性是 C 或者 C 时有用。 我们推荐你查阅 L 来得到更多信息。 =head2 初始化 Moose 提供一个选项叫做 C。这个会在构造函数中改变属性值。 =head1 作者 Moose 是由许多志愿者共同努力的结果。具体的请参看L 和 L译者:xiaomo(wxm4ever@gmail.com) =head1 版权和许可 This software is copyright (c) 2011 by Infinity Interactive, Inc.. 这是自由软件,您可以重新分配或者根据 Perl 5 的编程语言系统本身相关的条款进行修改。