*****************************************************
        *           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<Person> 类有 first
name 和 last name。属性对于类是可选的,好比并不是每一个
C<Person> 类都有社保号。

我们可以把类属性当作是成员的名字,通过这个名字我们可以读取或设置该成员的值。当然,属性还可以包括默认值、类型约束、委托方法等等。

在其他语言中,属性也被称为 slots 或 properties。

=head1 属性设置

通过 C<has> 来声明一个属性:

  package Person;

  use Moose;

  has 'first_name' => ( is => 'rw' );

这样就声明了有一个可读写的属性的类 C<Person>。

=head2 读写 vs 只读

通过 C<has>
传递的选项可以对属性进行相关设置。不过最简单也是最基本的是,你可以通过
C<is> 来设置变量的读取权限,read-only(ro) 或者
read-write(rw)。当设置为rw
时,你可以通过访问器来修改它的值。但设置为
ro时,你便只能读取该属性的值。

事实上,你可以不设置 C<is>,Moose
会默认使该属性没有任何存取权限。这对某些属性比较管用,如句柄等。但是
Moose
会抛出警告以防止程序员忘记书写存取规则。如果你确实需要这么做,那么可以通过设置
C<is> 为 C<bare> 来防止产生警告。

=head2 存取方法

每个属性有一个或多个存取方法,通过存取方法,你可以读取或者设置该属性的值

默认的存取方法和属性的名字一样。如果属性存取权限设置为
rw,则可以通过存取方法来读写属性值,反之,则不可以。

以上面的 C<Person> 类为例,我们有一个存取方法为
C<first_name>,通过这个存取方法我们可以读取或设置
C<Person> 实例的 C<first_name> 属性。

如果你愿意的话,你也可以指定具体的方法来进行存取操作。这对于你想要设置一个默认存取权限为
ro,但是可以通过某种方法来修改属性是非常方便的。

  has 'weight' => (
      is     => 'ro',
      writer => '_set_weight',
  );

这在以下场景中是非常方便的。比如,每当我们调用 C<eat>
方法的时候,我们可能会改变
weight,而在其他场景中我们对 weight 只有读取权限。

有些人喜欢把读取和设置方法分别来声明。在 I<Perl Best
Practices> 中,Damian
Conway也推荐读者使用"get_"和"set_"类方法。

我们可以通过具体的声明来做到。

  has 'weight' => (
      is     => 'rw',
      reader => 'get_weight',
      writer => 'set_weight',
  );

你认为这样一遍又一遍非常繁琐?你说的对,不过幸运的是,Moose
提供了相当强大的拓展系统,可以让你覆盖默认的命名约定。有关详细信息,请参阅
L<Moose::Manual::MooseX>。

=head2 断言和清理方法

Moose 允许你使用断言来判断一个属性是否已经被定义。

断言方法可以告诉你当前属性是否被定义。不过需要注意的是,当属性被设置为
C<undef>或者其他的一些假值,断言依然会返回 true。

清理方法会取消设置属性。这和设置属性为 C<undef> 是
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<required> 属性设置为 true。

  has 'name' => (
      is       => 'ro',
      required => 1,

值得一提的是,什么时候才是"required"。

基本上,当这个属性名必须被提供给构造函数,或者通过
default、builder来设置,这种情况下是 required。

如果你在一个必须属性上定义了清理方法,这个清理方法是I<可以>运行的,也就是说一个必须属性也是可以被取消设置的。

但是这样做大多是没有意义的,所以我们并不推荐这么做。

=head2 默认值和构造方法

属性可以设置默认值,而且 Moose
提供了两种方法来设置默认值。

最简单的,你可以通过 C<default> 来设置。

  has 'size' => (
      is        => 'ro',
      default   => 'medium',
      predicate => 'has_size',
  );

如果 size 属性没有提供给构造函数,那么 size
属性会被设置为默认值 C<medium>:

  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<default>
是在构造函数中开始运行的,所以会比一些属性更先运行。但当
C<default>依赖其他属性时就会出现一些问题。不过你可以通过设置属性为
C<lazy> 来解决。这个会在之后讲到。

如果你想在 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<builder> 方法来避开这一古怪的现象。

  has 'size' => (
      is        => 'ro',
      builder   => '_build_size',
      predicate => 'has_size',
  );

  sub _build_size {
      return ( 'small', 'medium', 'large' )[ int( rand 3 ) ];
  }

这个使用有以下几个好处。把对属性的操作移到一个代码块中,方便阅读与组织。这样子使用的话,也方便子类重载或者由一个
role 来实现。

我们强烈建议你使用 C<builder> 来初始化属性。它就是
C<default> 的增强版。

C<builder> 和 C<default>
作为类方法调用的,不接受额外的参数。

=head3 Builders 覆写

C<builder> 是通过名字来指定初始化函数的。所以 builder
方法是可以被继承和重载的。

比如我们继承 C<Person> 类,我们便可以重载 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<Moose::Manual::Roles>。

=head2 Laziness

Moose 允许你通过 C<lazy> 来推迟属性定义。

  has 'size' => (
      is      => 'ro',
      lazy    => 1,
      builder => '_build_size',
  );

当某属性 C<lazy> 为 true 时,该属性的 default
并不会在构造实例时运行,而是在相应的访问器访问时才进行计算。为什么要这样做呢?

首先,如果该属性的 default
值依赖于其他属性,那么该属性的 C<lazy> I<必须>为 true。

有一些情况下是不需要在该属性被请求前进行计算的。通过设置该属性为
C<lazy>,你可以有效的节省你的 CPU 时间。

我们建议你使用 builder 或者 lazy default。

=head2 构造函数的参数(C<init_arg>)

默认情况下,每个属性都可以通过名字传递给类。有时,你可能需要用一个略有不同的名字,或者你不想传递任何参数进去。

你可以通过 C<init_arg> 选项来做到以上的事情。

  has 'bigness' => (
      is       => 'ro',
      init_arg => 'size',
  );

现在我们有一个"bigness"属性,但是我们通过 C<size>
来传递到构造函数中。

你也可以通过如下方式设置不接受任何参数。

  has '_genetic_code' => (
      is       => 'ro',
      lazy     => 1,
      builder  => '_build_genetic_code',
      init_arg => undef,
  );

By setting the C<init_arg> to C<undef>, we make it impossible to set this
attribute when creating a new object.

=head2 循环引用

Moose 内置是支持 weak reference 的,可以通过设置 C<weak_ref>
为 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<undef> "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<trigger> 将在属性被设置的时候自动被调用。

  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<undef>。

这个与 C<after>
方法修饰符是有区别的。触发器只在属性被设置时被调用,而不是每当访问器访问时触发。触发器也会在构造函数运行时被调用。而
C<after> 方法修饰符不是。

注意,触发器不在 C<default> 或 C<builder> 之后被调用。

=head2 属性类型

属性类型可以限制只接受某些类型的值:

  has 'first_name' => (
      is  => 'ro',
      isa => 'Str',
  );

这表明 C<first_name> 属性是字符串类型。

Moose
还提供了一个快捷的方法来指定一个属性的类型,就是通过一个
role 来实现的。

  has 'weapon' => (
      is   => 'rw',
      does => 'MyApp::Weapon',
  );

关于属性类型的信息具体请查阅 L<Moose::Manual::Types>。

=head2 委托属性

Moose 可以定义委托属性来操作属性值。

  has 'hair_color' => (
      is      => 'ro',
      isa     => 'Graphics::Color::RGB',
      handles => { hair_color_hex => 'as_hex_string' },
  );

当调用 C<hair_color_hex> 时,会实际上调用
C<<$self->hair_color->as_hex_string>>。

关于委托属性的更多信息请查阅 L<Moose::Manual::Delegation>。

=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<Moose::Manual::MooseX>
中找到一些示例。关于"元类"和"继承"的更多信息请查阅
L<Moose::Cookbook>。

=head2 定义自己的委托属性

Native delegations 允许你定义 Perl 的数据结构。

比如,我们可以创建关于数组引用的
C<push()>,C<shift()>,C<map()>,C<count()>等方法。

  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<Moose::Manual::Delegation>。

=head1 属性继承

默认情况下,子类可以继承父类中所有的属性。你也可以在子类中重载它们。

继承一个属性,只需要简单的在前面加(C<+>):

  package LazyPerson;

  use Moose;

  extends 'Person';

  has '+first_name' => (
      lazy    => 1,
      default => 'Bill',
  );

现在子类中的 C<first_name> 属性是 lazy 的,而且默认值为
C<'Bill'>。

我们建议你在不是很了解的时候不要随便使用,尤其是涉及到类型(C<isa>)的时候。

=head1 多属性快捷创建

如果你有大量的属性仅仅是名字不同,你可以一次性的声明它们。

  package Point;

  use Moose;

  has [ 'x', 'y' ] => ( is => 'ro', isa => 'Int' );

因为 C<has>
也是一个函数,所以你也可以通过循环来创建。

  for my $name ( qw( x y ) ) {
      my $builder = '_build_' . $name;
      has $name => ( is => 'ro', isa => 'Int', builder => $builder );
  }

=head1 更多

Moose 属性是一个 big
topic,而这个文档只包含了一部分。我们建议你继续阅读L<Moose::Manual::Delegation>
和 L<Moose::Manual::Types> 来更全面的了解属性。

=head1 更多的选项信息

Moose
属性有许多选项。下面列出一些你可能会比较感兴趣的。

=head2 C<文档描述>

你可以为你的属性提供一个文档描述。

  has 'first_name' => (
      is            => 'rw',
      documentation => q{The person's first (personal) name},
  );

Moose 会把该描述存储起来。

=head2 C<序列化数据>

如果你的属性是一段数组引用或者 hash 引用,C<auto_deref>
这个设置会让 reader
来访问这个属性时,可以看到序列化以后的内容:

  my %map = $object->mapping;

当然这仅仅在你的属性是 C<ArrayRef> 或者 C<HashRef> 时有用。

我们推荐你查阅 L<Moose::Meta::Attribute::Native>
来得到更多信息。

=head2 初始化

Moose 提供一个选项叫做
C<initializer>。这个会在构造函数中改变属性值。

=head1 作者

Moose
是由许多志愿者共同努力的结果。具体的请参看L<Moose/CABAL>
和 L<Moose/CONTRIBUTORS>译者:xiaomo(wxm4ever@gmail.com)

=head1 版权和许可

This software is copyright (c) 2011 by Infinity Interactive, Inc..

这是自由软件,您可以重新分配或者根据 Perl 5
的编程语言系统本身相关的条款进行修改。