=encoding utf8 =head1 TITLE Synopsis 13: Overloading 纲要 13:重载 =head1 AUTHOR Larry Wall =head1 VERSION Maintainer: Larry Wall Date: 2 Nov 2004 Last Modified: 2 Dec 2004 Number: 13 Version: 3 =head1 Overview 概述 This synopsis discusses those portions of Apocalypse 12 that ought to have been in Apocalypse 13. 本纲要用以讨论启示录 12 中应该位于启示录 13 的部分。 =head1 Multiple dispatch 多重分派 The overloading mechanism of Perl 5 has been superseded by Perl 6's multiple dispatch mechanism. Nearly all internal functions are defined as C subs or C methods on generic types. Built-in operators are merely oddly named functions with an alternate call syntax. All you have to do to overload them is to define your own C subs and methods that operate on arguments with more specific types. Perl 5 中的重载机制将被 Perl 6 中的多重分派机制所取代。几乎所有的内部函数 都是由传递一般类的 C 子程序或 C 方法所定义。内置运算符不过是 奇怪的函数名加上不同的调用语法而已。要重载它们的话,你只需要定义你自己的 C 子程序和方法,然后通过指定特定类型的参数来达成目的。 For unary operators, this makes little effective difference, but for binary operators, multiple dispatch fixes the Perl 5 problem of paying attention only to the type of the left argument. Since both argument types are used in deciding which routine to call, there is no longer any trickery involving swapping the arguments to use the right argument's type instead of the left one. And there's no longer any need to examine a special flag to see if the arguments were reversed. 对于一元运算符,没有什么大变化。但对于二元运算符,多重分派修正了 Perl 5 中仅仅对左边的参数类型加以注意的错误。因为在多重分派中所有的参数类型 对你要调用哪个程序都有影响,所以再也不需要通过调换参数,用右边参数类型来代替 左边而达成调用欺骗。而且再也不需要检查一个特定标记来决定这个参数是否保留。 For much more about multiple dispatch, see A12. 需要更多关于多重分派的信息,请参考 A12. =head1 Syntax 语法 There is no longer any special C syntax separate from the declarations of the C routines themselves. To overload an existing built-in sub, say something like: 除了 C 程序申明外,再也没有任何特殊的 C 语法。 如果要重载一个已存在的内建子程序,这用这么写: multi sub *uc (TurkishStr $s) {...} Now if you call C on any Turkish string, it will call your function rather than the built-in one. Putting the C into the C<*> namespace makes it show up in everyone's packages, but as long as no one else defines a version of C on C, there's no collision. The types of the invocants are included in the "long name" of any C sub or method. 现在如果你用 土耳其/Turkish 字符串来调用 C, 那么它将调用你刚写的函数 而不是内建函数。将 C 放在 C<*> 命名空间可以让此子程序在所有人的 包/package 中使用,只用没有其他人也定义了一个 C 版本的 C ,那就没有任何冲突。 调用的类别将保护在任何 C 子程序或方法的“长名”内。 If you want to overload string concatenation for Arabic strings so you can handle various ligatures, you can say: 如果你想对 阿拉伯语/Arabic 字符串 重载字符串联以便处理不同的 连字/ligatures, 你可以这么写: multi sub *infix:<~>(ArabicStr $s1, ArabicStr $s2) {...} multi sub *infix:<~>(Str $s1, ArabicStr $s2) {...} multi sub *infix:<~>(ArabicStr $s1, Str $s2) {...} Ordinary methods can be turned into multi methods within the class definition: 一般方法可以在类定义中转换成 多重/multi 方法: class MyNum { multi method abs(MyNum $x) {...} ... } Likewise operators on your new type can appear in the class: 同样地,传递新类型的运算符也可以包含在类里: class MyNum { multi method prefix:<+> (MyNum $x) {...} # what we do in numeric context multi method prefix:<~> (MyNum $x) {...} # what we do in string context multi method prefix: (MyNum $x) {...} # what we do in boolean context ... } Binary operators may be declared as commutative: 二元运算符还可以被定义成可交换的: multi sub infix:<+> (Us $us, Them $them) is commutative { myadd($us,$them) } That's equivalent to: 这等同于: multi sub infix:<+> (Us $us, Them $them) { myadd($us,$them) } multi sub infix:<+> (Them $them, Us $us) { myadd($us,$them) } Note the lack of C<*> on those definitions. That means this definition of addition is only in effect within the scope of the package in which C<< infix:<+> >> is defined. Similar constraints apply to lexically scoped multi subs. Generally you want to put your multi subs into the C<*> space, however, so that they work everywhere. 注意这些定义中都没有 C<*>. 这表示新增的这个定义只对 C<< infix:<+> >> 所定义的 包作用域有效。相同的约束作用于在词法作用域的 多重/multi 子程序。不过通常你应该 将 多重/multi 子程序放在 C<*> 空间内,这样它们能在任何地方使用。 The C syntax had one benefit over Perl 6's syntax in that it was easy to alias several different operators to the same service routine. This can easily be handled with Perl 6's aliasing: C 语法相较于 Perl 6 语法还有个优点,它可以简单的使用别名让许多不同 的运算符使用同一个服务程序。通过 Perl 6 的别名,这也可以轻松搞定: multi sub unimpl (MyFoo $x) { upchuck(); } &infix:<+> ::= &unimpl; &infix:<-> ::= &unimpl; &infix:<*> ::= &unimpl; &infix: ::= &unimpl; =head1 Fallbacks 预设机制 Dispatch is based on a routine's signature declaration without regard to whether the routine is defined yet. If an attempt is made to dispatch to a declared but undefined routine, Perl will redispatch to C or C as appropriate to define the routine. This provides a run-time mechanism for fallbacks. By default, these declarations are taken at face value and do not specify any underlying semantics. As such, they're a "shallow" interpretation. 分派机制只是基于程序的声明信号,而不管这个程序是否已经被定义。如果试图分派 一个已声明却未定义的程序, Perl 将重分派到 C 或 C 来定义这个程序。这就提供了一个运行时的预设机制。默认这些声明将根据外表值来 判断而不指定任何潜在的语意。也就是说,这是种“浅层”解释。 However, sometimes you want to specify a "deep" interpretation of your operators. That is, you're specify the abstract operation, which may be used by various shallow operators. Any deep multi declarations will be "amplified" into all the shallow operators that can be logically based on it. If you say: 但是,有时候你需要对你的运算符指定一个“深层”解释。也就是说,你指定个抽象 运算符,它可能被多个浅层操作符所调用。任何一个深层多重声明都会被“扩大”到所有 逻辑上基于它的浅层运算符。 multi sub infix:<%> (Us $us, Them $them) is deep { mymod($us,$them) } then 那么 multi sub infix:<%=> (Us $us, Them $them) { $us = $us % $them } is also generated for you (unless you define it yourself). The mappings of magical names to sub definitions is controlled by the C<%?DEEPMAGIC> compiler hash. Pragmas can influence the contents of this hash over a lexical scope, so you could have different policies on magical autogeneration. The default mappings correspond to the standard fallback mappings of Perl 5 overloading. 也会被产生(除非你自己定义它)。 魔术名字(magical names)到子程序声明的映射由 C<%?DEFPMAGIC> 编译器散列 所约束。编译指示(Pargmas)能在词法作用域范围内影响这个散列的值,所以你 可以在魔术自动生成上有很多不同的策略。默认的映射与 Perl 5 重载的标准预设 映射相应。