2

这是一个 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);
4

2 回答 2

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

    Perl 中有一些原型的有效用例,但除非您知道为什么要这样设计代码,否则经验法则是永远不要使用原型。请参阅此 SO 帖子:

    为什么 Perl 5 的函数原型不好?

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


话说回来:

  • 您可以使用原型制作一个带有 1 个标量参数的子remCH($)原型
  • 您可以通过切换到面向对象的 Moose 框架来检查其类型的方法
于 2013-06-17T15:41:11.180 回答
6

Perl 没有类型签名或形式参数,这与 C 等其他语言不同:

// C code
int add(int, int);

int sum = add(1, 2);

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

传统的 Perl 方法

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

my $sum = add(1, 2);

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

如果您预先声明您的潜艇,您将获得以下信息:

  1. 您可以在没有括号的情况下调用潜艇
  2. 您可以使用“原型”更改解析参数的方式</li>

子程序原型

原型可以说

  • 在标量上下文中评估此参数sub foo($),或
  • 此参数必须是哈希变量,请将其作为参考传递sub foo(\%),或
  • 这个 sub 没有参数:sub foo()等。

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

您的错误源于您将 sub 声明为 nullary 的事实,这导致了parse error

签名

如果您希望能够使用命名参数声明子例程,则可以使用实现这些参数的模块。

  • 从 Perl 5.20 开始,您可以use feature 'signatures'. 它仍被标记为实验性的,但基本语法不太可能改变。

    use feature 'signatures';
    no warnings 'experimental::signatures'
    
    sub add($x, $y) { ... }
    
  • 有各种 CPAN 模块,例如Method::Signatures. 它们可能具有集成类型检查等优点,但也可能比在 Core Perl 中实现的解决方案更容易出错。

    use Method::Signatures;
    
    func add(Int $x, Int $y) { ... }
    

然而,这些“签名”与普通潜艇的原型无关。

于 2013-06-17T15:50:47.193 回答