Perl - Subroutines

Perl Subroutines或函数是一组一起执行任务的语句.您可以将代码分成单独的子例程.你如何在不同的子程序之间划分你的代码取决于你,但逻辑上这个除法通常是每个函数都执行一个特定的任务.

Perl可以互换地使用术语子程序,方法和函数.

定义并调用子程序

Perl编程语言中子程序定义的一般形式如下 :

sub subroutine_name {
   body of the subroutine
}

典型的调用Perl子程序的方法如下 :

subroutine_name( list of arguments );

在5.0之前的Perl版本中,调用子例程的语法略有不同,如下所示.这仍然适用于最新版本的Perl,但不推荐使用它,因为它绕过了子程序原型.

&subroutine_name( list of arguments );

让我们看看下面的例子,它定义了一个简单的函数,然后调用它.因为Perl在执行它之前编译你的程序,所以你在哪里声明你的子程序并不重要.

#!/usr/bin/perl

# Function definition
sub Hello {
   print "Hello, World!\n";
}

# Function call
Hello();

当执行上述程序时,它会产生以下结果 :

Hello, World!

将参数传递给子程序

您可以将各种参数传递给子程序,就像使用任何其他编程语言一样并且可以使用特殊数组@_在函数内部进行访问.因此函数的第一个参数在$ _ [0]中,第二个参数在$ _ [1]中,依此类推.

你可以将数组和散列作为参数传递给任何参数标量但传递多个数组或散列通常会导致它们失去独立的身份.因此,我们将使用引用(在下一章中解释)来传递任何数组或散列.

让我们尝试下面的示例,它接受一个数字列表,然后打印它们的平均值:

#!/usr/bin/perl

# Function definition
sub Average {
   # get total number of arguments passed.
   $n = scalar(@_);
   $sum = 0;

   foreach $item (@_) {
      $sum += $item;
   }
   $average = $sum / $n;

   print "Average for the given numbers : $average\n";
}

# Function call
Average(10, 20, 30);

当执行上述程序时,它会产生以下结果 :

Average for the given numbers : 20

将列表传递给子程序

因为@_变量是一个数组,它可以用于向子程序提供列表.但是,由于Perl接受并解析列表和数组的方式,从@_中提取单个元素可能很困难.如果你必须传递一个列表和其他标量参数,那么将list作为最后一个参数,如下所示 :

#!/usr/bin/perl

# Function definition
sub PrintList {
   my @list = @_;
   print "Given list is @list\n";
}
$a = 10;
@b = (1, 2, 3, 4);

# Function call with list parameter
PrintList($a, @b);

当执行上述程序时,它会产生以下结果 :

Given list is 10 1 2 3 4

将哈希值传递给子程序

当您向哈希提供哈希值时接受列表的子例程或运算符,然后哈希自动转换为键/值对列表.例如 :

#!/usr/bin/perl

# Function definition
sub PrintHash {
   my (%hash) = @_;

   foreach my $key ( keys %hash ) {
      my $value = $hash{$key};
      print "$key : $value\n";
   }
}
%hash = ('name' => 'Tom', 'age' => 19);

# Function call with hash parameter
PrintHash(%hash);

当执行上述程序时,它会产生以下结果 :

name : Tom
age : 19

从子程序返回值

您可以返回子程序中的值,就像你在任何其他编程语言中所做的那样.如果你没有从子程序返回一个值,那么在子程序中最后执行的任何计算自动也是返回值.

你可以像子程序一样返回子程序中的数组和哈希值,但是返回多个数组或散列通常会导致它们失去独立的身份.所以我们将使用引用(在下一章中解释)从函数返回任何数组或散列.

让我们尝试下面的例子,它接受一个数字列表然后返回它们的平均值 :

#!/usr/bin/perl

# Function definition
sub Average {
   # get total number of arguments passed.
   $n = scalar(@_);
   $sum = 0;

   foreach $item (@_) {
      $sum += $item;
   }
   $average = $sum / $n;

   return $average;
}

# Function call
$num = Average(10, 20, 30);
print "Average for the given numbers : $num\n";

当执行上述程序时,它会产生以下结果 :

Average for the given numbers : 20

子程序中的私有变量

默认情况下,Perl中的所有变量是全局变量,这意味着可以从程序中的任何位置访问它们.但您可以随时使用 my 运算符创建名为词汇变量私人变量.

我的运算符将变量限制在可以使用和访问它的特定代码区域.在该区域之外,不能使用或访问此变量.该区域称为其范围.词法范围通常是一个带有一组括号的代码块,例如定义子例程的主体或者标记的代码块的那些代码块,如果,while,for,foreach, eval 语句.

以下是一个示例,说明如何使用 my 运算符 :

sub somefunc {
   my $variable; # $variable is invisible outside somefunc()
   my ($another, @an_array, %a_hash); # declaring many variables at once
}

让我们检查以下示例以区分全局和私有变量 :

#!/usr/bin/perl

# Global variable
$string = "Hello, World!";

# Function definition
sub PrintHello {
   # Private variable for PrintHello function
   my $string;
   $string = "Hello, Perl!";
   print "Inside the function $string\n";
}
# Function call
PrintHello();
print "Outside the function $string\n";

当执行上述程序时,它会产生以下结果 :

Inside the function Hello, Perl!
Outside the function Hello, World!

通过local()的临时值

本地主要用于当前变量的值必须对被调用的子例程可见.本地只是为全局(意味着包)变量提供临时值.这称为动态范围.词法范围是用my完成的,它更像C的自动声明.

如果给本地提供了多个变量或表达式,它们必须放在括号中.此运算符的作用是将这些变量的当前值保存在隐藏堆栈的参数列表中,并在退出块,子例程或eval时恢复它们.

让我们检查以下示例来区分全局和局部变量之间 :

#!/usr/bin/perl

# Global variable
$string = "Hello, World!";

sub PrintHello {
   # Private variable for PrintHello function
   local $string;
   $string = "Hello, Perl!";
   PrintMe();
   print "Inside the function PrintHello $string\n";
}
sub PrintMe {
   print "Inside the function PrintMe $string\n";
}

# Function call
PrintHello();
print "Outside the function $string\n";

当执行上述程序时,它会产生以下结果 :

Inside the function PrintMe Hello, Perl!
Inside the function PrintHello Hello, Perl!
Outside the function Hello, World!

状态变量通过state()

还有另一种类型的词法变量,类似于私有变量但是它们保持状态,并且在多次调用子程序时不会重新初始化.这些变量是使用 state 运算符定义的,并且从Perl 5.9.4开始可用.

让我们检查以下示例以演示 state

#!/usr/bin/perl

use feature 'state';

sub PrintCount {
   state $count = 0; # initial value

   print "Value of counter is $count\n";
   $count++;
}

for (1..5) {
   PrintCount();
}

当执行上述程序时,它会产生以下结果 :

Value of counter is 0
Value of counter is 1
Value of counter is 2
Value of counter is 3
Value of counter is 4

在Perl 5.10之前,你必须像这样写下它 :

#!/usr/bin/perl

{
   my $count = 0; # initial value

   sub PrintCount {
      print "Value of counter is $count\n";
      $count++;
   }
}

for (1..5) {
   PrintCount();
}

子程序调用上下文

子程序或语句的上下文定义为返回预期值.这允许您使用单个函数,该函数根据用户期望接收的内容返回不同的值.例如,以下localtime()在标量上下文中调用时返回一个字符串,但在列表上下文中调用它时返回一个列表.

my $datestring = localtime( time );

在这个例子中,$ timestr的值现在是一个由当前日期和时间组成的字符串,例如,Thu Nov 30 15:21: 33 2000.相反&减去;

($sec,$min,$hour,$mday,$mon, $year,$wday,$yday,$isdst) = localtime(time);

现在各个变量包含localtime()子例程返回的相应值.