[Perl]Moose::Manual::Types-Moose 的类型系统
什么是 Perl 的类型
Moose 提供自己的属性的类型系统。你也能使用 MooseX 模块帮助你来验证类中方法上的参数。
Moose 的类型系统是基于一个Perl 5中的自己的隐式类型的组合和一些 Perl6 的概念。您可以创建自定义约束的 subtypes,因此很容易写出表达任何类型来做参数验证。
类型都有一个名字,你也可以重命名使用他们的名字空间,所以很容易地共享类型到所有的大型应用程序。
但,这并不是真实的类型系统, 它只是一个更加高级的参数检查的系统。可以让你的参数通过一个约束的名字来进行检查。
虽然这行说,它仍然是相当的有用的,我们认为这是使用 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 |
实际上, Any 和 Item 只是概念上不同。Item 是作为一些参数类型层次结构中的顶级类型。注 HashRef[Int] 这种结构中,Int 是指的 Hash 的值必须是 Int 型。
这些 types 的其余部分对应于现有的 Perl 的概念。特别是:
BOOL 类型认为 1 为真和 undef, 0或空字符串作为假。
[`A] 可以接受 `a 或者 undef。
Num 接受任何 Perl 认为的数字(详见在 Scalar::Util 模块中的"looks_like_number")。
ClassName 和 RoleName 接受字符串(类名称或角色名称)。类/角色是必须已经载入了并经过约束检查后的。
FileHandle 可以接受一个 IO::Handle 对象或一个内置的 Perl 的文件句柄(详见在 Scalar::Util 模块中的“openhandle)。
Object 接受任何 blessed 过的引用 。
"[`a]" 的类型可以被参数化。因此,不是只是简单的 ArrayRef,比如,我们希望 ArrayRef[Int] 来代替这个。我们甚至可以放入 HashRef[ArrayRef[Str]] .
在这类型当中 “参数类型项[`a]” 特别值得在提一提。单独使用,它并不能表示真实的任何东西(等效于 Item )。在这当它代替着一个参数类型项,这意味着要么是 undef 或 Item 中参数的类型。所以 “参数类型项[`a]”表示一个整数,或者undef。
更加详细的类型结构层次,可以看 Moose::Util::TypeConstraints.
什么是类型
你需要意识到重要的,类型并不是一个类(或包)。类型只是对象名字和属性约束(准确的讲是 Moose::Meta::TypeConstraint 对象中)。Moose 会维护一个全局的注册过的类型名字。对象可以被转换成相应的名称,如 Num。
然而,类名可以是类型名称。当你使用 Moose 定义一个新的类时,它自动关联的定义了一个相关的类型名称(这时类型名等于类名):
package MyApp::User; use Moose; |
现在你可以使用 'MyApp::User' 的类型名了。因为自动会生成这样一个类型名。
has creator => ( is => 'ro' , isa => 'MyApp::User' , ); |
但是,在非 Moose 的类中是不能这样的,这时您可能需要显式声明类的类型。这会让你有点糊涂,因为 Moose 的类中为属性设了一个 ISA 选项,可以在其中设置任何未知类型的名称。所以可以这样:
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 都会假设这个 DateTime 是一个类名。
SUBTYPES(子类型)
Moose 使用的子类型( subtypes)是其内置的层次结构中的 。例如,int 是 Num 中的一个子类型。
子类型是定义在父类型和约束下的。首先检查由父(S)中定义的任何约束,其次是子类型定义的约束,一个有效的子类型的值必须通过所有这些检查。
通常情况下,子类型会使用父的约束,使其达到更加具体的约束。
每个子类型也可以定义自己约束失败的信息,比如你见到的出错信息"你提供的值为 20,他不是一个有效的值。这个值必须是 1 - 10",这比默认定义的信息更加友好。默认类型检查只会提示这个值无效。还有一个更加友好的做法,安装 Devel::PartialDump 这个模块。这时 Moose 会使用这个来解析并显示未知的值。
这是一个简单有用的子类型的例子。
subtype 'PositiveInt' , as 'Int' , where { $_ > 0 }, message { "The number you provided, $_, was not a positive number" }; |
注意这个中的语法糖都是由 Moose::Util::TypeConstraints 中导出来的。
类型名
类型名在 Perl 的环境中是全局存在的。在 Moose 内部,会给注册的名字映射到类型对象中。
如果你在同一个进程中有多个 apps 或者函数库使用了 Moose .你可能会发生一些名字冲突的问题。所以推荐你给你的类型名字加个相同的前缀,来防止这种类型的碰撞。
例如,调用“PositiveInt”类型,而不是调用的 "MyApp::Type::PositiveInt" 或 "MyApp::Types::PositiveInt".。我们建议你集中定义在叫 MyApp::Types 一个单一的包名中,这样当前包还是可以使用这个来加载您的应用程序中的其他类。
然而,在您这样做前,建议你应该看看在 MooseX::Types 模块。此模块可以很容易地创建一个“类型库(type library)”模块,它可以导出你的类型,如 Perl 常数。
has 'counter' => (is => 'rw' , isa => PositiveInt); |
这使得你可以使用一个简短的名称而不需要到处都使用完全限定名( fully qualify the name),它还允许您轻松地创建参数类型:
has 'counts' => (is => 'ro' , isa => HashRef[PositiveInt]); |
这个模块会在编译的时候就检查你的名字,这个模块它通常在解析较复杂的字符串类型时更加健壮。
强制类型转换
建议继续学习:
- linux file命令是如何识别文件的类型的 (阅读:3915)
- PHP上传文件类型彻底判断方案及PHP+nginx上传大小彻底控制方案 (阅读:3825)
- PHP JAVA C上传文件如何准确判断文件类型-mime知识普及 (阅读:3540)
- 检查 Linux 下线程库的类型 (阅读:2616)
- 类型转换-无处不在的陷阱 (阅读:2244)
- Zend Parameters Parser新增类型描述符介绍 (阅读:2302)
- JavaScript 类型浅解 (阅读:2318)
- 类型的本质和函数式实现 (阅读:2097)
- java enum枚举类型用法小结 (阅读:1875)
- 三谈类型问题:ECMAScript为什么错了? (阅读:1443)
QQ技术交流群:445447336,欢迎加入!
扫一扫订阅我的微信号:IT技术博客大学习
扫一扫订阅我的微信号:IT技术博客大学习
- 作者:扶凯 来源: 扶凯
- 标签: 类型
- 发布时间:2011-09-25 13:36:03
- [66] Oracle MTS模式下 进程地址与会话信
- [65] 如何拿下简短的域名
- [65] Go Reflect 性能
- [59] 【社会化设计】自我(self)部分――欢迎区
- [59] IOS安全–浅谈关于IOS加固的几种方法
- [59] 图书馆的世界纪录
- [59] android 开发入门
- [53] 视觉调整-设计师 vs. 逻辑
- [47] 界面设计速成
- [47] 读书笔记-壹百度:百度十年千倍的29条法则