
        *****************************************************
        *           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::Types - Moose 的类型系统

=head1 VERSION

version 2.0401

=head1 和 Perl 的类型相似？

Moose 拥有自己的类型系统。你也可以配合 MooseX
模块用来进行参数验证。

Moose 的类型系统是根据 Perl 5 的默认类型以及 Perl 6
的一些新概念而来的。当然，你也可以自己定义新的类型。

每个类型都有一个名字，你可以通过命名空间重复使用它们，所以很容易的在大型应用程序中共享类型。

然而，这不是一个"实际"的类型系统。Moose
不会奇迹般的使 Perl
关联类型的变量，这只是一个比较先进的类型检查系统，可以让你的参数通过约束的名字来进行检查。

尽管那样说，Moose
类型系统仍然是非常有用的，而且它是我们认为 Moose
强大的原因之一。好好的使用 Moose
类型系统，可以方便我们得到有效的数据，以及更好的维护我们的程序。

=head1 Moose 类型

基本的 Moose 类型层次结构看起来时这样的。

  Any
  Item
      Bool
      Maybe[`a]
      Undef
      Defined
          Value
              Str
                  Num
                      Int
                  ClassName
                  RoleName
          Ref
              ScalarRef[`a]
              ArrayRef[`a]
              HashRef[`a]
              CodeRef
              RegexpRef
              GlobRef
                  FileHandle
              Object

在实践中，C<Any> 和 C<Item> 是有概念性的区别的。C<Item>
是层次结构中的顶层类型。

这些类型的其余部分对应于现有的 Perl 的概念。特别是：

=over 4

=item 

C<Bool> 接受 C<1> 为 true, 接受 undef, 0, 或者空字符串为
false。

=item 

C<Maybe[`a]> 接受 C<`a> 或 C<undef>。

=item 

C<Num> 接受任何 perl
认为的数字。（详见 L<Scalar::Util/looks_like_number>）

=item 

C<ClassName> 和 C<RoleName>
接受字符串（类名或角色名）。当约束被检查时，类或角色必须已经被载入。

=item 

C<FileHandle> 接受 L<IO::Handle> 或者 Perl 内建句柄。（详见
L<Scalar::Util/openhandle>)

=item 

C<Object> 接受被绑定的引用。

=back

"[`a]" 的类型可以被参数化。因此，不是只有简单的
C<ArrayRef>，也可以使用C<ArrayRef[Int]>，甚至是
C<HashRef[ArrayRef[Str]]>。

C<Maybe[`a]>
需要特别说明下。当你只是单独使用它的时候，它没有任何意义。但当被参数化后，就表明它的值是
C<undef> 或者是参数化的类型。所以，C<Maybe[Int]>
表示整数或者 C<undef>。

想要了解更多的类型结构的细节，请查阅
L<Moose::Util::TypeConstraints>。

=head1 什么是类型？

你需要意识到类型不是一个类（或包）。类型只是对象名字和属性约束（准确的讲是L<Moose::Meta::TypeConstraint>）。Moose
会维护一个全局的注册过的类型名字。对象可以转换成相应的名称，如
C<Num>。

然而， 类名I<可以>是类型名称。当你使用 Moose
定义一个新的类时，它会自动关联的定义一个相关的类型名称：

  package MyApp::User;

  use Moose;

现在你就可以用 C<'MyApp::User'> 做为一个类型名称：

  has creator => (
      is  => 'ro',
      isa => 'MyApp::User',
  );

但是，非 Moose
类是不能这样的。这时你需要显示的声明类型信息。

  has 'birth_date' => (
      is  => 'ro',
      isa => 'DateTime',
  );

一般情况下，当 Moose
见到一个未知的名字时，都会假设这个名字是一个类名。

  subtype 'ModernDateTime'
      => as 'DateTime'
      => where { $_->year() >= 1980 }
      => message { 'The date you provided is not modern enough' };

  has 'valid_dates' => (
      is  => 'ro',
      isa => 'ArrayRef[DateTime]',
  );

在上面这两个实例中，Moose 都会假设这个 C<DateTime>
是一个类名。

=head1 子类型

Moose 在其内建的层次结构中也有子类型。如，C<Int> 就是
C<Num> 的子类型。

子类型是在父类型和约束下的。子类型的值必须先通过父类型的约束检验，然后再通过自己的约束检验，才是有效的值。

也就是说，子类型会通过父类型的约束和自己的约束来达到更加具体的约束。

子类型也可以定义自己约束检测失败时的消息。比如你可能会见到如下出错信息"你提供的值为20，它不是一个有效的值，有效的值必须是1-10"。这种错误信息比默认定义的更加友好。还有一个更加友好的方法，你可以通过
L<Devel::PartialDump> 来得到更加友好提示信息。

这里有一个简单但是有用的例子：

  subtype 'PositiveInt',
      as 'Int',
      where { $_ > 0 },
      message { "The number you provided, $_, was not a positive number" };

注意，所有关于类型的语法糖在 L<Moose::Util::TypeConstraints>
中被提供。

=head1 类型名称

类型名称在 Perl 的环境中是全局存在的。Moose
会把注册的名称映射到类型对象中。有关注册过程，请见
L<registry|Moose::Meta::TypeConstraint::Registry>。

如果你在同一个进程中有多个 apps 或者函数库使用
Moose，可能会有一些名字冲突。所以我们推荐你在你的类型名字前加前缀。

如，定义类型名称为"MyApp::Type::PositiveInt"，而不是"PositiveInt"。我们建议你集中定义所有的类型在
C<MyApp::Types> 中，这样也方便于移植。

不管怎样，在你那样做之前，我们建议你去看看
L<MooseX::Types>
模块。这个模块可以帮助你创建一个"类型库"，这个库可以很方便的导入到你的程序中。

  has 'counter' => (is => 'rw', isa => PositiveInt);

这使得你可以使用一个简短的名称而不需要到处都使用完全限定名。它还允许你轻松的创建参数类型：

  has 'counts' => (is => 'ro', isa => HashRef[PositiveInt]);

这个模块会在编译时进行检查，而且它通常在解析比较复杂的字符串类型时更加强壮。

=head1 强制类型转化

强制类型转化可以让 Moose
帮你将一个类型转换成另外一个类型。

  subtype 'ArrayRefOfInts',
      as 'ArrayRef[Int]';

  coerce 'ArrayRefOfInts',
      from 'Int',
      via { [ $_ ] };

你会发现我们并没有在 C<ArrayRef[Int]>
的基础上进行强制转化，这是因为 Moose
不推荐在原生类型上进行强制转化。

强制类型转换是全局的，就像类型名称，所以一个内建类型被强制转化后，整个程序都会使用转化后的类型。这就是上面提到的另一个使用良好命名空间的原因。

Moose
I<绝对不会>自己对类型进行强制转化，除非你通过设置
C<coerce> 选项为 true来明确要求。

  package Foo;

  has 'sizes' => (
      is     => 'ro',
      isa    => 'ArrayRefOfInts',
      coerce => 1,
  );

  Foo->new( sizes => 42 );

此代码示例是正确的，创建的新对象将有C<[ 42 ]>作为其
C<sizes> 的属性。

=head2 递归转化

递归转化是转化类型参数的类型参数。让我们看下面这个例子：

  subtype 'HexNum',
      as 'Str',
      where { /[a-f0-9]/i };

  coerce 'Int',
      from 'HexNum',
      via { hex $_ };

  has 'sizes' => (
      is     => 'ro',
      isa    => 'ArrayRef[Int]',
      coerce => 1,
  );

如果我们传递十六进制数组的引用给 C<sizes>，Moose
不会为我们转化。

然而，你可以通过定义一个子类型使其在两个参数类型间进行转化。

  subtype 'ArrayRefOfHexNums',
      as 'ArrayRef[HexNum]';

  subtype 'ArrayRefOfInts',
      as 'ArrayRef[Int]';

  coerce 'ArrayRefOfInts',
      from 'ArrayRefOfHexNums',
      via { [ map { hex } @{$_} ] };

  Foo->new( sizes => [ 'a1', 'ff', '22' ] );

现在 Moose 将会强制转化十六进制数为整数。

Moose
不会尝试级联的强制转化，所以它不会强制转化单一的十六进制数。所以要做到这一点，我们需要定义一个单独的强制类型转化：

  coerce 'ArrayRefOfInts',
      from 'HexNum',
      via { [ hex $_ ] };

虽然这样写很冗长，但是在这个强制类型转化的魔法中，我们认为这样是最好的，因为这样写会非常清楚。

=head1 类型联合

Moose
允许你声明一个属性为一个或一个以上不同的类型。比如下面这个例子：

  has 'output' => (
      is  => 'rw',
      isa => 'Object | FileHandle',
  );

Moose
会解析这个字符串，并认出你正在创建的类型是什么。C<output>
属性会接受任何类型的对象或未绑定的句柄。

当你使用类型联合的时候，你应该仔细考虑是否强制转化是个更好的解决方法。

对于我们上面的例子，使用对象的 C<print>
方法是个更好的解决方法。

  duck_type 'CanPrint', [qw(print)];

我们可以转化句柄到一个对象，只需要简单的封装这个类：

  package FHWrapper;

  use Moose;

  has 'handle' => (
      is  => 'rw',
      isa => 'FileHandle',
  );

  sub print {
      my $self = shift;
      my $fh   = $self->handle();

      print {$fh} @_;
  }

现在我们能定义一个从 C<FileHandle>
到我们封装的类的强制转化：

  coerce 'CanPrint'
      => from 'FileHandle'
      => via { FHWrapper->new( handle => $_ ) };

  has 'output' => (
      is     => 'rw',
      isa    => 'CanPrint',
      coerce => 1,
  );

这种模式使用一个类型转化，而不是一个类型联合，这将使你的类内部更加简单些。

=head1 类型创建助手

L<Moose::Util::TypeConstraints>
中包含创建指定类型的一些助手函数，包括C<class_type>，C<role_type>，C<maybe_type>
和 C<duck_type> 等等。具体的请查阅文档。

一个比较有用的就是 C<enum> 类型，它允许你创建一个有
C<Str> 的子类型，让你指定它可能出现的值。

  enum 'RGB', [qw( red green blue )];

这样就创建了一个叫做 C<RGB> 的类型。

=head1 匿名类型

创建类型的函数均返回类型的对象。这个对象可以被用在任何可以使用的地方。

  has 'size' => (
      is  => 'ro',
      isa => subtype( 'Int' => where { $_ > 0 } ),
  );

这对于你只想使用一次的类型，是非常方便的，你不需要纠结于给它起一个什么样的名字。

=head1 确认方法的参数

Moose 不提供任何验证方法的参数手段。不过，也有几个
CPAN 上的拓展可以让你这么做。

最简单的就是使用 L<MooseX::Params::Validate>
模块，这个可以让你通过Moose
的类型来对你的参数进行检查。

  use Moose;
  use MooseX::Params::Validate;

  sub foo {
      my $self   = shift;
      my %params = validate_hash(
          \@_,
          bar => { isa => 'Str', default => 'Moose' },
      );
      ...
  }

L<MooseX::Params::Validate> 也支持类型强制转化。

也有一些更强大的拓展来支持参数的验证，只要加载
L<MooseX::Method::Signatures>模块，这个模块会给我们提供相关的关键字的。

  method morning ( Str $name ) {
      $self->say("Good morning ${name}!");
  }

=head1 加载顺序问题

因为 Moose
的类型是在运行时声明的，所以你可能会遇到一些加载顺序问题。特别是，你可能使用一个类的类型约束，在此之前这个类型已经定义过了。

为了改善这个问题，我们推荐你定义你I<所有>的类型在一个模块中，然后在其他的模块中加载这个模块。

=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
的编程语言系统本身相关的条款进行修改。


