尽管括号可以省略,我们还是应该总是在调用子程序的时候加上括号,即使不提供任何参数,读者就能更容易发现子程序的调用。
在子程序中,参数被保存在@_
中。例如:
Perl以引用方式调用
不像其他主流编程语言,Perl以引用方式调用子程序(译者注:以引用方式传递参数)。这意味着子程序中用到的变量或值不是实参的副本,它们本身就是实参。
my $x = 7;
sub reassign {
$_[0] = 42;
}
reassign($x);
print $x; # "42"
如果你尝试这样做:
reassign(8);
程序就会因为错误而终止运行,因为reassign()
的第一行就相当于
8 = 42;
这边可以学到的经验教训是,在子程序中你总是应该在使用参数之前将它们提取出来。
提取参数
我们有不止一种方法来提取@_
中的参数,但总有一些方法比其他方法更好。
下面的示例子程序left_pad
在字符串左边填充某个字符直到达到需要的长度。(x
函数将同一个字符串的多个副本连接起来。)(注意:为了简化问题,这些子程序都缺乏必要的错误检查,比如确保填充字符串长度为1,检查要求的宽度是否大于等于字符串的长度,需要的参数是否都提供了。)
left_pad
通常就像下面这样调用:
逐个抽取
@_
中的参数很有效,但也并不是那么地美观:sub left_pad {
my $oldString = $_[0];
my $width = $_[1];
my $padChar = $_[2];
return $newString;
}
-
sub left_pad {
my $oldString = shift @_;
my $width = shift @_;
my $padChar = shift @_;
my $newString = ($padChar x ($width - length $oldString)) . $oldString;
return $newString;
}
如果没有给
shift
函数提供array参数,它就会默认对@_
进行操作。这种用法很常见:sub left_pad {
my $oldString = shift;
my $width = shift;
my $padChar = shift;
my $newString = ($padChar x ($width - length $oldString)) . $oldString;
return $newString;
}
超过4个参数以后就很难搞清楚参数的哪部分被赋值给谁了。
你也可以一次性把所有
@_
中的参数提取出来。仍然是适用于少于4个参数的情形:
返回值
sub contextualSubroutine {
# 调用这里需要一个列表,那么就返回一个列表
return ("Everest", "K2", "Etna") if wantarray;
# 调用者需要一个scalar,那么就返回一个scalar
return 3;
}
my @array = contextualSubroutine();
print @array; # "EverestK2Etna"
my $scalar = contextualSubroutine();