Perl函数声明

时间:2013-06-17 15:37:33

标签: perl prototype declaration

这是一个Perl n00b问题,但我没有找到一个清晰易懂的在线回答。

我有这段代码:

1.sub remCH();
2.#some stuff
3.$line = remCH($line);
4.
5.sub remCH() {
6.$rem = shift;
7.$rem = chomp($rem);
8.return ($rem);
9.}

执行此代码时,我总是遇到以下错误(第24行将在上面的代码中为第3行):

Too many arguments for main::rem_CRLF at ./make_csv.pl line 24, near "$line)" 

根据我的理解,这是因为函数设置为返回一些东西但是当我声明它时,它被声明为“void”。

如何声明如下函数???

sub remCH(string/integer);

2 个答案:

答案 0 :(得分:6)

  • 您应该只是删除第1行中的函数声明(或Perl中已知的“prototype”)。您的错误是因为原型(remCH())声明函数具有“零参数”签名,而您的调用将其传递给一个参数。返回类型与它无关。

    在Perl中有一些有效的原型用例,但除非你知道为什么要用这种方式设计代码,否则经验法则是永远不要使用原型。见SO帖子:

    Why are Perl 5's function prototypes bad?

  • 另外,根据plusplus的明智评论,我错过了你在第5行的函数定义中有“()”。与C不同,你在Perl中不需要它们 - 请放弃它们。他们将函数定义转换为另一个原型。


说完了:

  • 您可以使用remCH($)原型
  • 对带有1个标量参数的子进行原型设计
  • 您可以通过切换到面向对象的Moose框架来检查其类型的方法

答案 1 :(得分:4)

与其他语言(如C:

)不同,Perl没有类型签名或形式参数
// C code
int add(int, int);

int sum = add(1, 2);

int add(int x, int y) {
  return x + y;
}

相反,参数只是作为一个平面列表传递。任何类型验证都发生在您的代码中;你必须手动写这个。您必须自己将arglist解压缩到命名变量中。而且您通常不预先声明子例程:

my $sum = add(1, 2);

sub add {
  my ($x, $y) = @_; # unpack arguments
  return $x + $y;
}

如果你预先确定你的潜艇,你会得到以下结果:

  1. 你可以在没有parens的情况下召唤潜艇
  2. 您可以使用“prototypes”
  3. 更改参数的解析方式

    原型可以说

    • 在标量上下文中评估此参数sub foo($)
    • 此参数必须是哈希变量,请将其作为参考传递sub foo(\%)
    • 此子句不带参数sub foo()等等。

    请勿使用这些来验证参数的数量。实际上,根本不要使用它们;他们在远处引起行动。它们也不适用于类型验证。

    您的错误源于您将sub声明为nullary,这导致解析错误


    如果您希望能够使用命名参数声明子例程,则可以使用实现这些参数的模块。有几点需要注意:

    • 这些模块并不普及,因此只能将它们用于可移植性不成问题的内部项目。
    • 他们只在新的perls上工作
    • 他们经常弄乱你的行号:(

    一个好的实现是Method::Signatures,它还允许类型(和值)验证:

    use Method::Signatures;
    
    my $sum = add(1, 2);
    
    func add(Int $x, Int $y) {
      return $x + $y;
    }
    

    然而,这些“签名”与普通潜艇的原型没有没有