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