Perl 5 不是一个彻头彻尾面向对象的语言。其核心数据类型(标量、数组和哈希)也非有 方法让你重载的对象。即便如此,你还是 能够 控制你编写的类和对象的行为,特别是 当它们在各类上下文中强制类型转换或求值。这称为 重载(Overloading)。
重载隐晦而强大。一个有趣的例子就是重载对象在布尔上下文中的行为,特别是在你使用如 空对象(Null Object)模式(http://www.c2.com/cgi/wiki?NullObject)时。在布尔上 下文中,对象为真……但仅在你不对布尔化操作进行重载的情况下。
你可以重载几乎所有的对象操作:字符串化、数值化、布尔化、迭代、调用、数组访问、哈 希访问、算术操作、比较操作、智能匹配、按位操作甚至赋值。
最为有用的通常也是最为常见的:字符串化、数值化以及布尔化。overload
编译命令允许你 将函数和可重载操作关联起来。下面就是一个重载布尔求值的类:
在所有布尔上下文中,此类所有实例求值得假。
overload
编译命令的参数是一个键值对,键描述了重载的类型而值则是替代 Perl 默认行为 的函数引用。
添加字符串化也是很容易的:
重载数值化操作则更为复杂,因为算术操作符倾向于执行二元操作(arity)。给出 两个重载了加法的操作数,如何确定优先级?答案应是一致的、易于解释、便于未阅读 实现源码的人理解的。
perldoc overload
意图在标有 Calling Conventions for Binary Operations 和 MAGIC AUTOGENERATION 的两个小节中解释这一切,但最简单的解决方法是重载数值化 操作并告诉 overload
在可能时将提供的重载操作用作后备:
将 fallback
设为真值使 Perl 在可能的情况下使用其他已定义的重载操作来合成所 要求的操作。如果不行,Perl 将表现得好像未经任何重载那样。这通常是你想要的。
没有 fallback
,Perl 将仅使用由你提供的特定重载操作。如果某人尝试进行未经你 重载的操作,Perl 将会抛出异常。
子类继承祖先重载的操作。它们可以以两种方法中的一种覆盖这个行为。如果父类如所示 使用重载操作,函数引用直接提供,则子类 必须 直接通过 overload
覆盖父类的 重载行为。
父类可通过指定执行重载操作所调用的方法 名称 来允许其子代更为灵活,而非将函数 硬性编码:
子类在不直接用 overload
时只能覆盖指定的方法。
重载也许看上去像是一种富有诱惑力的工具,用于产生新操作的符号快捷方式。IO::All
CPAN 发行模块极尽此特性之能事,为简明、可复合的代码提供聪明的点子。还有各类通过 合理利用重载而精炼的出色 API,使众多混乱凝固下来。有时最好的代码会出于简单直接的 设计而避开灵巧。
因为加法、乘法还有拼接操作记法已经到处都是,针对 Matrix(矩阵)
类重载这些操作 还可以说得通。一个全新的问题领域则无需刻意重载这些操作────你没必要因此将现存 Perl 操作符弄得一词二义。
Damian Conway 的著作 Perl 最佳实践(Perl Best Practices) 建议另行将重载用于防 止对对象的意外滥用。举例来说,将无法用单一数值表达的对象上的数值化操作重载为 croak()
可以帮助你在实际程序中找到真正的缺陷。Perl 5 中重载还是比较少见的,但是这条建议可以 提升程序的可靠性和安全性。
Hey! The above document had some coding errors, which are explained below:
- Around line 5:
-
A non-empty Z<>
- Around line 12:
-
Deleting unknown formatting code U<>