重新定义子程序时没有足够的参数

Not enough arguments when redefining a subroutine

当我重新定义自己的子例程(而不是 Perl 内置函数)时,如下所示:

perl -ce 'sub a($$$){} sub b {a(@_)}'

我收到此错误:

Not enough arguments for main::a at -e line 1, near "@_)"

我想知道为什么。

编辑:

"redefine"这个词可能选错了。但就我而言(我可能应该解释一下我最初尝试做的事情),我想通过在测试结果。

这是我所做的:

Test::More.pm :

sub is ($$;$) {
    my $tb = Test::More->builder;

    return $tb->is_eq(@_);
}


MyModule.pm :

sub is ($$;$) {
   my $t    = gmtime(time);
   my $date = $t->ymd('/').' '.$t->hms.' ';

   print($date);
   Test::More::is(@_);
}

你在这里没有重新定义任何东西。

你已经通过说 sub a($$$) 为你的子 a 设置了 prototype。函数定义中的美元符号告诉 Perl 这个 sub 恰好有三个标量参数。当你用 a(@_) 调用它时,Perl 不知道该列表中将有多少元素,因此它不知道调用将有多少参数,并在编译时失败。

不要乱用原型。你可能不需要它们。

相反,如果您知道您的子程序需要三个参数,请在您调用它的地方明确获取它们。

sub a($$$) {
    ...
} 

sub b {
    my ($one, $two, $three) = @_; 
    a($one, $two, $three);
}

或者更好的是,根本不使用原型。


此外,ab 都是糟糕的名字。不要使用它们。

您为子程序提供的原型(从 Test::More::is 复制)表明您的子程序需要两个强制参数和一个可选参数。传入单个数组将不满足该原型 - 它被视为将在标量上下文中评估的单个参数。

解决方法是检索传递给子例程的两个(或三个)参数,并将它们分别传递给 Test::More::is

sub is ($$;$) {
   my ($got, $expected, $test_name) = @_;

   my $t    = gmtime(time);
   my $date = $t->ymd('/').' '.$t->hms.' ';

   print($date);
   Test::More::is($got, $expected, $test_name);
}

问题与您使用原型或您正在重新定义子程序无关(严格来说,您不是因为两个子程序在不同的包中),但这是因为 Test::More::is() 有一个原型。

在 Perl 中,原型不会像改变解析规则那样验证参数。 $$;$ 表示 sub 期望调用者匹配 is(EXPR, EXPR)is(EXPR, EXPR, EXPR).

在这种情况下,绕过原型是最理想的。

sub is($$;$) {
   print gmtime->strftime("%Y/%m/%d %H:%M:%S ");
   return &Test::More::is(@_);
}

既然你不关心Test::More::is是否修改了你的@_,下面是一个简单的优化:

sub is($$;$) {
   print gmtime->strftime("%Y/%m/%d %H:%M:%S ");
   return &Test::More::is;
}

如果 Test::More::is 使用 caller,您会发现以下内容很有用:

sub is($$;$) {
   print gmtime->strftime("%Y/%m/%d %H:%M:%S ");
   goto &Test::More::is;
}