考虑这个程序,我在参数列表中构造一个Array。虽然有一个接受数组的签名,但这会调用接受List的那个:
foo( [ 1, 2, 3 ] );
multi foo ( Array @array ) { put "Called Array @ version" }
multi foo ( Array $array ) { put "Called Array \$ version" }
multi foo ( List $list ) { put "Called List version" }
multi foo ( Range $range ) { put "Called Range version" }
我从一个意外的例行程序得到输出:
Called Array $ version
如果我取消注释其他签名,则会调用该签名:
Called List version
为什么不调用( Array @array )
版本?调度员如何做出决定(以及记录在哪里)?
答案 0 :(得分:5)
为什么不调用(Array @array)版本?
您的测试foo
调用只有一个数组([1,2,3]
)作为参数,而不是数据 Array
s(例如[[1,2,3],[4,5,6]]
)。
(@
中的@array
表示does Positional
的值,例如数组或列表。Array @array
表示相同的内容,但附加约束是每个元素数组,列表或其他任何内容Array
。)
调度员如何做出决定?
简化,选择最窄的匹配类型:
multi foo ( Array ) {} # Narrowest
multi foo ( List ) {} # Broader
multi foo ( Positional ) {} # Broader still
multi foo ( @array ) {} # Same as `Positional`
(Diagram of subtype relationships of Array
, List
and Positional
。)
有关详细信息,请参阅jnthn's authoritative answer to a related SO question。
(在哪里记录)?
我对这个文件不太确定。 Multi-dispatch看起来很小。
答案 1 :(得分:1)
我犯了一个非常愚蠢的错误,这就是为什么我没有看到我的预期。您无法约束以@
开头的变量。任何约束都适用于其元素。 Array @array
表示我有一个位置排序的东西,其中每个元素都是Array
。这是the same thing that raiph said。奇怪的是,语法看起来是一样的,但它做了不同的事情。这是我以前绊过的东西。
由于它做了不同的事情,即使数据结构匹配也不会有效:
foo( [ [1], [2], [3] ] );
foo( [ 1, 2, 3 ] );
multi foo ( Array @array ) { put "Called Array @ version" }
multi foo ( Array $array ) { put "Called Array \$ version" }
multi foo ( List $list ) { put "Called List version" }
multi foo ( Range $range ) { put "Called Range version" }
我仍然可以根据约束和数据结构获得我不希望的版本:
Called Array $ version
Called Array $ version
我认为这只是普通用户必须学习的Perl 6瑕疵之一。
答案 2 :(得分:0)
设计文件(更完整但更过时)与文档(已知不完整,如docs.perl6.org承认,但希望更新)之间似乎存在权衡。前者解释了Synopsis 12中的多子分辨率。摘录:
当您使用特定的短名称调用例程时,如果有多个可见的长名称,则它们都被视为候选者。根据参数的运行时类型与每个候选参数的声明类型的匹配程度,它们按顺序排序。最佳候选人被召唤,除非有平局,在这种情况下,并列候选人将使用任何其他决胜局策略进行重新分配(见下文)。 [...]
有三种打破模式,按绝望的顺序递增:
A)内部或衍生范围
B)运行时约束处理
C)使用标有"的候选人是默认"
决胜局A优先选择内部或更多派生范围内的候选人而不是外部或较少派生范围内的候选人。对于同一范围内的候选人,我们进入决胜局B.
在没有任何限制的情况下,决胜局A的关系立即故障转移到决胜局C;如果没有被C解决,他们会在编译时警告一个模糊的调度。 [...]
我不太了解Perl 6是否可以证明其准确性,但它似乎与raith’s answer一致,并且还包括其他内容。