这篇文章的标题说明了一切。关键是调用函数X
应该与被调用函数Y
的签名无关。 IOW,X
应该只传递给Y
, en masse ,它所收到的所有参数(X
),最后留给Y
如果签名关闭,则抱怨。
我认为这只是一个问题
sub X {
return Y( @_ );
}
......但显然不是:
sub getpwuid_wrapper {
return getpwuid( @_ );
}
上面的包装器不仅仅是包装:
DB<7> p getpwuid( 5 )
gamesx560games/usr/games/usr/sbin/nologin
DB<8> p getpwuid_wrapper( 5 )
daemonx11daemon/usr/sbin/usr/sbin/nologin
下一位给出了可能发生的事情的线索:
DB<9> p getpwuid( 1 )
daemonx11daemon/usr/sbin/usr/sbin/nologin
我认为getpwuid( @_ )
被解释为getpwuid( scalar @_ )
,原因超出了我的理解范围。
注意: getpwuid
只是举例说明问题。在实践中,需要这种传递功能,主要是在运行时之前不知道将要调用的函数;例如当此函数是回调时。
答案 0 :(得分:7)
您遇到的问题是因为getpwuid
的原型为$
,导致它在标量上下文中解释其参数。
您可以从以下单行中看到这一点:
perl -e 'print prototype("CORE::getpwuid"), "\n"'
...打印$
。
所以当你将@_
传递给getpwuid
时,你是对的;它在标量上下文中被传递并传递了@_
包含的元素数量。
一种解决方案是使用goto
的子例程形式,它使用相同的调用堆栈和传递给其调用者的参数调用其操作数。
这是一个单行形式的例子:
perl -e 'print getpwuid(5), "\n"; print sub{ getpwuid(@_) }->(5), "\n"; print sub { goto &CORE::getpwuid }->(5), "\n";'
在此示例中,第一次和第三次调用将通过&#39; 5&#39;到getpwuid
,但第二次调用将通过scalar(@_)
,在这种情况下为1
。
另一个hackish选项是检测您正在调用的函数是否具有使用prototype
函数的原型,并做出相应的反应。但这有问题。首先,您已经知道您正在调用getpwuid
- 无需在运行时进行检测。即使你出于某种原因必须在运行时检测到,一些CORE::
函数也会为它们的原型返回undef
因为它们使用了一个无法用我们可用的原型选项表示的函数({{ 1}},例如)。
在这种特殊情况下,因为你已经知道你正在调用什么函数,并且已经知道它的原型,它可能最容易做到这一点:
system
更新:在运行perl -e 'print sub { getpwuid(shift) }->(5), "\n";'
可能是一个好方法之前,调用的子程序是不可知的。但是,goto
要注意的一件事是,你永远不会回到父子;正在进行的子程序将直接返回到父子的调用者。
另一种选择是使用goto
前缀和无参数调用目标子。这也可以将&
传递给它,但是以绕过原型的方式。这是一个例子:
@_
这似乎与perl -e 'print sub { &CORE::getpwuid }->(5)'
方法类似,但不会修改调用堆栈,并将返回到父子。