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

时间:2015-10-18 18:53:54

标签: perl

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

1 个答案:

答案 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)' 方法类似,但不会修改调用堆栈,并将返回到父子。