尽管括号可以省略,我们还是应该总是在调用子程序的时候加上括号,即使不提供任何参数,读者就能更容易发现子程序的调用。

    在子程序中,参数被保存在@_中。例如:

    Perl以引用方式调用

    不像其他主流编程语言,Perl以引用方式调用子程序(译者注:以引用方式传递参数)。这意味着子程序中用到的变量或值不是实参的副本,它们本身就是实参。

    1. my $x = 7;
    2. sub reassign {
    3. $_[0] = 42;
    4. }
    5. reassign($x);
    6. print $x; # "42"

    如果你尝试这样做:

    1. reassign(8);

    程序就会因为错误而终止运行,因为reassign()的第一行就相当于

    1. 8 = 42;

    这边可以学到的经验教训是,在子程序中你总是应该在使用参数之前将它们提取出来。

    提取参数

    我们有不止一种方法来提取@_中的参数,但总有一些方法比其他方法更好。

    下面的示例子程序left_pad在字符串左边填充某个字符直到达到需要的长度。(x函数将同一个字符串的多个副本连接起来。)(注意:为了简化问题,这些子程序都缺乏必要的错误检查,比如确保填充字符串长度为1,检查要求的宽度是否大于等于字符串的长度,需要的参数是否都提供了。)

    left_pad通常就像下面这样调用:

    1. 逐个抽取@_中的参数很有效,但也并不是那么地美观:

      1. sub left_pad {
      2. my $oldString = $_[0];
      3. my $width = $_[1];
      4. my $padChar = $_[2];
      5. return $newString;
      6. }
      1. sub left_pad {
      2. my $oldString = shift @_;
      3. my $width = shift @_;
      4. my $padChar = shift @_;
      5. my $newString = ($padChar x ($width - length $oldString)) . $oldString;
      6. return $newString;
      7. }

      如果没有给shift函数提供array参数,它就会默认对@_进行操作。这种用法很常见:

      1. sub left_pad {
      2. my $oldString = shift;
      3. my $width = shift;
      4. my $padChar = shift;
      5. my $newString = ($padChar x ($width - length $oldString)) . $oldString;
      6. return $newString;
      7. }

      超过4个参数以后就很难搞清楚参数的哪部分被赋值给谁了。

    2. 你也可以一次性把所有@_中的参数提取出来。仍然是适用于少于4个参数的情形:

    返回值

    1. sub contextualSubroutine {
    2. # 调用这里需要一个列表,那么就返回一个列表
    3. return ("Everest", "K2", "Etna") if wantarray;
    4. # 调用者需要一个scalar,那么就返回一个scalar
    5. return 3;
    6. }
    7. my @array = contextualSubroutine();
    8. print @array; # "EverestK2Etna"
    9. my $scalar = contextualSubroutine();