我正在尝试解决this issue,这实际上是由this other stackoverflow question提出的,与callwith
和samewith
的不同行为有关。后者似乎已明确定义,但是callwith
并不清楚。
查看此示例:
proto how-many(|) {*}
multi sub how-many( Pair $a, Pair $b ) {
say "Int $a and $b";
return "There are $a and $b"
}
multi sub how-many( $a, $b ) {
say "Not int $a and $b";
my $calling = callwith( 1 => $a, 2 => $b );
return $calling;
}
say how-many( "little piggie","littler piggie" );
根据文档,callwith
应该呼叫下一个匹配的候选者。但是,这是输出:
Not int little piggie and littler piggie
(Any)
因此,它正在调用how-many
的第二个版本,然后(显然)调用一个不存在的函数,并返回Nil
,它作为Any
传递到调用例程。
我也尝试过使用不同的签名,但这也不起作用。文档中的示例显然表明,仅当变量属于相同的类层次结构时,该示例才有效。是这样吗可能不是,因为将位置签名更改为Any $a, Any $b
也不起作用,也不更改声明的顺序。
上面,用
callwith
更改samewith
显然可以工作,但是我想了解callwith
的工作原理,而不是使上面的代码起作用。
此外,它似乎在类层次结构中向下移动,但不是向上。这个example in roast(Perl 6测试套件)可以工作:
my $tracker = '';
multi d($x) { $tracker ~= 'Any' ~ $x };
multi d(Int $x) { $tracker ~= 'Int'; callwith($x+1); $tracker ~= 'Int' };
lives-ok { d(3) }, 'can call callwith inside a multi sub';
但是,如果我们进行更改,以使我们从层次结构的底部使用callwith
,则如下所示:
my $tracker = '';
multi d($x) { $tracker ~= 'Any' ~ callwith( "called-with" => $x) };
multi d(Pair $x) { $tracker ~= "Pair $x" };
say d( 3 );
失败并
Use of Nil in string context in sub d at rewrite-test-callwith.p6 line 6
这是预期的行为吗?
答案 0 :(得分:9)
callwith
,nextwith
,callsame
和nextsame
中的所有对象将按由原始参数确定的候选集进行遍历。因此,尽管callwith
可以用来替换参数,但这只是它的全部工作。不会导致迭代的预定候选列表发生变化。
考虑以下三个候选人:
multi foo(Any $x) { say "In Any case with $x" }
multi foo(Real $x) { say "In Real case with $x"; callwith($x.Int); }
multi foo(Int $x) { say "In Int case with $x"; callsame(); }
我们可以使用.cando
并向其传递Capture
来询问哪些候选人。因此:
.say for &foo.cando(\(42));
将产生以下输出:
sub foo (Int $x) { #`(Sub|78402328) ... }
sub foo (Real $x) { #`(Sub|78412816) ... }
sub foo ($x) { #`(Sub|78412968) ... }
由于所有3位候选人都匹配。调用foo(42)
将产生以下输出:
In Int case with 42
In Real case with 42
In Any case with 42
通过对比,与:
.say for &foo.cando(\(4.2));
输出为:
sub foo (Real $x) { #`(Sub|78412816) ... }
sub foo ($x) { #`(Sub|78412968) ... }
调用foo(4.2)
会使callwith
遍历这些候选者:
In Real case with 4.2
In Any case with 4
在最一般的候选人中,callwith
或类似人物不会产生任何影响,并且将得出Nil
的数字。
尽管此处的示例具有多个子,但包装器和非多重方法也是如此,它们也遍历了预定列表。
最后,还值得观察一下,如果每次都有一个新的调度,我给出的示例最终将以无限递归的方式结束。通过遍历预定的候选人列表,这永远不会发生。
请注意,以上所有内容均不适用于samewith
,而test01.php
的存在正是为了进行全新的调度。