函数如何将它透明接收的所有参数传递给另一个函数?

kjo*_*kjo 1 perl

这篇文章的标题说明了一切.关键是调用函数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只是举例说明问题.在实践中,人们需要这种传递功能,主要是直到运行时才知道将要调用的函数; 例如,当此功能是回调时.

Dav*_*idO 7

你面临的问题是因为它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方法类似,但不会修改调用堆栈,并将返回到父子.

  • 你也可以传递`@_ [0 .. $#_]` (3认同)