在perl中,子声明中带括号的$表示什么?

dav*_*veg 3 perl

我必须调试其他人的代码并遇到看起来像这样的子声明...

sub mysub($$$$) {
    <code here>
}
Run Code Online (Sandbox Code Playgroud)

...也...

sub mysub($$$;$) {
    <code here>
}
Run Code Online (Sandbox Code Playgroud)

带括号的“ $”(带有可选的“;”)列表是什么意思?我进行了一个实验,似乎不关心是否我向以这种方式声明的子项传递的参数比在列表中的“ $”少得多。我当时在想,它可能会被用来消除两个具有相同名称的不同子对象的歧义,只是区别在于所加参数的数量(由($$$$)vs($$$)vs($$)定义)等...)。但这似乎并非如此。

bri*_*foy 8

那是一个Perl子例程原型。让解析器知道需要多少参数是一种古老的方法。除非您知道他们将为您做什么,否则建议您在任何新代码中都避免使用它们。如果可以避免使用原型,请避免使用。它并没有像您想的那样使您受益。有一种新的但实验性的方法可以做得更好。

后面的元素;是可选参数。因此,mysub($$$$)具有四个强制参数,并且mysub($$$;$)具有三个强制参数和一个可选参数。

有关解析的一些知识

当您要指定参数时,Perl让您对括号略为放松,因此它们是相同的:

print "Hello World";
print( "Hello World\n" );
Run Code Online (Sandbox Code Playgroud)

这是Perl的哲学要点之一。当我们可以省略样板时,我们应该可以。

另外,Perl允许您将任意多的参数传递给子例程,而您不必提前声明任何参数:

sub some_sub { ... }
some_sub( 1, 2, 3, 4 );
some_sub 1, 2, 3, 4;   # same
Run Code Online (Sandbox Code Playgroud)

这是Perl的另一个基本思想:我们有标量和列表。列表上有很多东西,我们不在乎列表中的内容或元素有多少。

但是,某些内建函数带有一定数量的参数。该sin恰恰一个参数(但print需要零到无穷大有效):

print sin 5, 'a'; # -0.958924274663138a  (a is from `a`)
Run Code Online (Sandbox Code Playgroud)

rand接受零或一个:

print rand;    # 0.331390818188996
print rand 10; # 4.23956650382937
Run Code Online (Sandbox Code Playgroud)

但是,您可以定义自己的子例程。原型是一种模仿您在内建函数中看到的相同行为的方式(我认为这很酷,但对生产情况却没有激励作用)。

我倾向于在参数列表中使用括号,因为我发现人们更容易理解我的意图(尽管print我猜并非总是如此):

print sin(5), 'a';
Run Code Online (Sandbox Code Playgroud)

我喜欢一种有趣的原型。您可以制作自己的语法,例如mapgrep阻止形式:

map { ... } @array;
Run Code Online (Sandbox Code Playgroud)

如果您想解决这个问题(但仍然不希望维护程序员接受),请查看Object :: Iterate进行演示。

实验签名

Perl v5.20引入了实验性签名功能,您可以在其中给参数命名。所有这些都是必需的:

use v5.20;
use feature qw(signatures);
sub mysub ( $name, $address, $phone ) { ... }
Run Code Online (Sandbox Code Playgroud)

如果需要可选参数,则可以为其指定默认值:

sub mysub ( $name, $address, $phone = undef ) { ... }
Run Code Online (Sandbox Code Playgroud)

由于这是一项实验性功能,因此在您每次使用它时都会发出警告。您可以将其关闭:

no warnings qw(experimental::signatures);
Run Code Online (Sandbox Code Playgroud)

  • 我还要补充一点:除非您正在查看现有代码,否则除非您试图弄清楚这意味着什么,否则,除非有很少的例外,否则绝对不要使用它们。它们改变了函数调用的解析方式(例如,将`@ foo`传递给此函数将传递`@ foo`的大小)。对于预期的参数验证功能,您需要[签名](https://perldoc.pl/perlsub#Signatures)。 (2认同)