我在这个问题中的假设是,我指定的签名完全描述了方法将接受的所有内容 . 显然我错了,但无论如何我想要那样做 . 如果我没有在签名中指定它,我不希望其他人能够提供它作为一个认为它会做某事的论据 .
我为方法创建了一个带有单个位置参数的签名,我希望它只接受单个位置参数 . 但是,它也接受命名参数而无需投诉:
class SomeClass {
method something ( Int $n ) { 'Ran something' }
}
put SomeClass.something: 137; # Ran something
put SomeClass.something: 137, :foo('bar'); # Ran something
但是,如果我定义一个采用命名参数的方法,'s called each time I define it second. Also, although I think I' ve说它需要一个命名参数 foo
,它不是必需的,它仍然接受我没有指定的命名参数:
class SomeClass {
multi method something ( Int $n ) { 'Ran something' }
multi method something ( Int $n, :$foo ) { "Ran $foo" }
}
put SomeClass.something: 137; # Ran
put SomeClass.something: 137, :foo('bar'); # Ran bar
put SomeClass.something: 137, :bar('foo'); # Ran
所以,有些问题:
-
如何指定包含我想接受的所有内容的签名并排除其他所有内容?
-
如何强制Perl 6选择最接近的匹配签名?
-
Perl 6以什么顺序决定检查方法?
3 回答
您正在谈论有关多方法调度最难掌握的事情之一 . 最重要的是要实现每个
method
签名都有一个隐含的*%_
(也就是一个slurpy哈希),如果没有指定的话 . 这意味着它将吃掉任何非特定的命名参数 .您需要意识到的第二件事是,命名参数只能起到打破平局的作用 . 因此,如果有多个候选者具有相同的位置参数匹配集,MMD将使用第一个有效的候选者(考虑到
%_
所有意外的命名参数):这个看似意外的结果是由以下事实引起的:
两个候选者具有相同数量的位置参数
第一个候选匹配,因为
:$foo
是可选的和
:bar
被隐含*%_
吃掉为了使它更像您期望的工作,您需要将需要打破的候选项放入您希望它们触发的顺序,并使任何命名参数成为必需参数:
如果您有候选者采用多个命名参数,它很快就会变得相当复杂,只要有一个使用
%_
内省的方法,你可能会更好:希望这会让事情更加清晰:-)
方法总是带有隐式
*%_
参数,cf这是设计理念,认为子类可以选择他们喜欢的参数,然后通过
nextsame
等进行重新调度(参见design docs - 不确定在哪里,或者甚至在其他地方记录) .有几种方法可以拒绝未声明的命名参数,例如通过where子句
或通过空的子签名
传递非声明参数时,前者将失败
和后者
我将留下多方法调度的确切语义供其他人回答,但我的启发式经验法则是确保所需的命名参数被声明为(即
!
存在)并将更通用的方法放在最后 .我认为
Int $n, :$foo
比Int $n
更具体的签名 . 你可以强制使用foo
或者第一次签名更严格