代码之家  ›  专栏  ›  技术社区  ›  bam500

重新定义子例程时参数不足

  •  0
  • bam500  · 技术社区  · 8 年前

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

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

    我收到以下错误:

    main::a at-e行1,靠近“@\u”的参数不足

    我想知道为什么。

    编辑:

    “重新定义”这个词可能选择得不好。但在我的情况下(我可能应该解释一下我最初试图做什么),我想通过打印测试结果之前的第一个日期和时间来重新定义(这里“重新定义”是有意义的)Test::More::是函数。

    以下是我所做的:

    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(@_);
    }
    
    3 回复  |  直到 8 年前
        1
  •  7
  •   Dave Cross    8 年前

    您已给出子例程的原型(复制自 Test::More::is )表示您的子例程需要两个必需参数和一个可选参数。传入单个数组并不能满足原型的要求-它被视为单个参数,将在标量上下文中进行计算。

    修复方法是检索传递给子例程的两个(或三个)参数,并将它们分别传递给 测试::更多::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() 有一个原型。

        2
  •  5
  •   Community Mohan Dere    6 年前

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

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

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

    相反,如果您知道sub需要三个参数,请在您调用它们的地方显式获取它们。

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

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


    而且 b 都是可怕的名字。不要使用它们。

        3
  •  4
  •   ikegami Gilles Quénot    8 年前

    在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;
    }
    

    如果 测试::更多::is 使用 caller ,您会发现以下内容很有用:

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