Perl 中的具名实体————变量和函数————可按 属性 的形式附加额外的元信息。属性是 名称(通常,也是值),它允许某种形式的元编程(code_generation)。
用最简单的形式来说,属性是一个附加于变量或函数声明上的前置冒号标识符:
如果合适类型(分别是标量和函数)的属性处理器存在,这些声明将引发对名为 hidden
和 ScienceProject
的属性处理器的调用。如果合适的处理器不存在,Perl 会抛出编译 期异常。这些处理器可以做 任何事。
属性可以包括一个参数列表;Perl 将它们作为一个常量字符串列表,即使它们可能会类似于 其他值,如,数字或变量。来自 CPAN 的 Test::Class
模块很好地利用了这一参数形式:
Test
属性标识了包括测试断言的方法,并且可选地标识了意图执行的断言方法的数量。 虽然对这些类的内省(reflection)可以发现合适的测试方法,当给出经良好设计的启发 式方法,:Test
属性使得代码及其意图毫无歧义。
setup
和 teardown
参数允许测试类定义它们自己的支持方法而不必担心重名或其他 因继承或其余设计上的考虑而引发的冲突。你 可以 强制施行某种设计,其中所有测试类 必须自行覆盖名为 setup()
和 teardown()
的方法,但是属性方式给与实现更多的灵 活性。
属性确实有它们的缺点:
属性的正式编译命令(即
attributes
)已经将其接口列为“实验性质”很多年了。 Damian Conway 的核心模块Attribute::Handlers
简化了它们的实现。请在可能时采用 它而非attributes
;任何声明属性处理器的模块必须 继承
Attribute::Handlers
以使处理器对 所有用到它们的包可见 你也 可以 将它们存放在UNIVERSAL
,但这是对全局的污染, 还是一种糟糕的设计。。此缺点归根于 Perl 5 自身对属性的实现方式;属性处理器生效于
CHECK
代码块,使得它们不适合用于那些修改语法分析及编 译顺序的项目,例如 mod_perl;任何提供给属性的参数是一列常量字符串。
Attribute::Handlers
进行部分数据 转换,但偶尔你需要禁用它。
属性中最差的一点就是它们会远距离产生奇怪的语法动作。给出一段使用属性的代码,你 能否预言它的行为?良好而准确的文档可以帮助你,但如果一段看上去很无辜的词法变量 声明将此变量的引用存放他处,则你对销毁该变量内容的期待将是错误的,除非你非常仔 细地阅读文档。类似的,处理器可能会用一个函数包装另一个函数并在你不知情的情况下 在符号表里替换了它————考虑一个自动调用 Memoize
的 :memoize
属性。
复杂的特性可以产生紧凑和惯用语化的代码。Perl 允许开发者实验多种设计以便找到他们 想法的最佳表示。属性和其他高级 Perl 特性可以帮助你解决复杂的问题,但是他们也会混 淆原本简单的代码意图。
大多数程序绝对不会用到这个特性。
Hey! The above document had some coding errors, which are explained below:
- Around line 5:
-
A non-empty Z<>
- Around line 75:
-
Deleting unknown formatting code N<>